Giter VIP home page Giter VIP logo

csf.orm's Introduction

This repository contains six closely-related NuGet packages which facilitate development using ORM software tools and NHibernate in particular.

The packages

  • CSF.Entities
  • CSF.ORM
  • CSF.ORM.Entities
  • CSF.ORM.NHibernate4
  • CSF.ORM.NHibernate5
  • CSF.PersistenceTester

Documentation

Documentation for each of these packages is available on the wiki for this repository.

Open source license

All source files within this project are released as open source software, under the terms of the MIT license.

csf.orm's People

Contributors

craigfowler avatar

Watchers

James Cloos avatar  avatar

csf.orm's Issues

Crash when using the persistence tester with NUnit3, due to lazy-loading outside of the session

When using the persistence tester, if persistence fails and an error result is returned, there can be a crash error when inspecting that result because references may be lazily-loaded outside of the scope of the ISession used by the test.

The issue here is that during the Assert stage, in order to display friendly results to the user, the ToString() method is executed on objects which have not yet been fetched from the DB. This causes a crash during the test instead of showing the actual test results.

A possible solution (for consideration)

A possible solution (unsure whether to go with this or not) would be to get the ToString() result ahead of time in the persistence tester, when creating the result object. If exceptions occur then catch and swallow them because there's nothing we can do at that point.

Additionally, at the assert stage of the test, if getting an object value causes an exception, simply record the exception and otherwise swallow it. In the summary print something like <[InvalidOperationException] raised reading this value>, so the user knows which exception was raised, but still sees results.

To discover impact and a potential bug, identity and entity equality across class hierarchies should be investigated

There is a potential bug in the way in which entities are compared for equality.

Say we have a base class Animal with two subclasses: Cat and Dog.

Cat ID 5 and Dog ID 5 could both exist in the same application, if the underlying data-store used a 'table per concrete class' relational model for storing entities.

In the above scenario, I think that the entity equality mechanism would consider them to be equal even though they are not.

If the underlying database were using 'table per class' or 'single table' then this would not be an issue, because two entities of different types (in the same class hierarchy) cannot have the same identity.

This must be investigated to determine its impact and, if it is a true bug, a solution devised.

To provide maximum compatibility, decide upon compile targets for the aspects of this project

This project will likely contain a number of different packages:

  • CSF.ORM
  • CSF.Entities
  • CSF.ORM.Entities
  • CSF.ORM.NHibernate
  • CSF.PersistenceTester

These will largely be renamed versions of existing projects.

The first three of these libraries have no direct dependency upon any ORM. They could target a number of frameworks and permit wide support.

The last two, though, have a direct dependency upon NHibernate. I am aware that NHibernate 4.x is only available for .NET Framework 4.x, whereas NHibernate 5.x is built for netstandard.

This might mean that libraries which support NHibernate must be split into separate packages which support different framework stacks depending upon the version of NHibernate which they need to support.

There is some information available which suggests that NuGet package dependencies can be grouped and varied by framework/runtime target.

This way I could say that in .NET Framework 4.5 target, we depend upon only NHibernate 4.x but in netstandard we can accept 5.x and up.

To sanity-check this project, ideas from a rejected NHibernate feature request should be evaluated

There has been an issue raised on the NHibernate project, subsequently rejected, which requests support for mocking ISession and the Linq queries/extension methods.

That's a large part of the purpose of this project. In that comment thread/discussion there are other ideas discussed, along with links to other sources. This all needs evaluating in the context of this project. It could be that there are better solutions available for what I want to do.

To formalise functionality & provide a stable platform, the API for ORM operations must be documented

The ORM part of this library is mainly about creating an abstraction for the use of ORMs (primarily NHibernate) so that I may test logic, whilst detached from the ORM itself.

This ticket is to formally design and document the API of that abstraction.

Missing functionality

The current API is missing some useful bits of functionality which I frequently use from NHibernate.

Lazy queries

  • ToLazy<T>()
  • ToLazyValue<T,V>(Expression<Func<IQueryable<T>,V>>)

Eager loading

  • EagerlyFetch<P,C>
  • EagerlyFetchMany<P,C>
  • ThenEagerlyFetch<P,C,GC>
  • ThenEagerlyFetchMany<P,C,GC>

Implementation notes

These functions must be implemented as extension methods. However, I want their actual implementation logic to be contained within a normal service which may be injected.

I will need to expose a static method which allows me to substitute the implementation which 'drives' these extension methods.

I also need to create some in-memory implementations of these functions, so that they may be provided by no-op logic, for testing purposes.

Review NHibernate-related types with a view to splitting-away those which don't relate to the ORM API

The NHibernate library should mainly be about implementations of the ORM API defined elsewhere in the solution. However, it has picked up a number of unrelated types which are for NHibernate but which aren't for the ORM.

These should be split away into projects of their own, do that they may be used independently of the ORM API.

This ticket is to review those types and split them away where applicable.

The static Identity class should either be included or deleted

It has become apparent that the static Identity class is not compiled a part of the project.

I'm not entirely sure now as to why this is the case. Is it that I planned to deprecate and remove this functionality, or perhaps it should be compiled and included (and it's a mistake that it's not).

This ticket it to investigate, find out why, and then either delete it altogether or include it in the compiled library. Once that's done a new version should be published.

The identity factory must not crash when a compatible identity value is used

Currently, the identity factory requires an identity value to be an exact type match for the desired identity value.

For example, of an entity requires Int64, then an identity cannot be created using an Int32, even though it is compatible/has an implicit cast available. This ticket is to relax that restriction so that compatible types may be used.

Sample exception & stack trace

System.ArgumentException : Identity type `Int64' was specified but provided identity value was a `System.Int32'.
Parameter name: identityValue
  at CSF.Entities.IdentityFactory.Create (System.Type entityType, System.Type identityType, System.Object identityValue)
  at CSF.Entities.Identity.Create[TEntity] (System.Object identityValue)

To publish libraries for reuse, they must be made available via NuGet

All libraries in this repo except for tests should be made available via NuGet.

Checklist

  • Version numbers to be correct for every package
  • License correctly listed in built package
  • Project/repository URL correct
  • Remaining package metadata
  • Multi-targeting where appropriate: NHibernate 5 packages won't support net45
  • Old/obsolete packages must be de-listed in NuGet

Packaging error means NHibernate packages are not installable

The two CSF.ORM.NHibernateX packages (for NH 4 & 5) cannot be installed. This is because they depend upon the nonexistent CSF.ORM.NHibernate.Common package. The Common library isn't intended to be a NuGet package, it's another library, bundled inside the NH4 and NH5 packages.

I need to remove the dependency which the dotnet build system has implicitly added from the NHibernate impl projects into the NHibernate common project.

It looks like there's some advice on how to do this in this dotnet/NuGet feature request, particularly the workaround linked from the bottom of the issue description. This might be as simple as using PrivateAssets="all" in the reference. I have already handled the copying of the build assets over. It's only the unwanted package dependency that is causing me a problem.

To avoid duplication, archive repositories which have been merged into this one

This repository is made from the merger of five others. These other five should now be archived and updated to point here.

These other repositories should be archived so that they no longer accept new commits. They should also be updated with a message pointing here, so that readers can find the new development.

Possibly keep the CSF.Data.NHibernate repo?

The repository CSF.Data.NHibernate might need to be kept; see issue #16, because I think that some of its contents don't belong in this repo.

Delete deprecated types

As of the version 2 release, types marked as deprecated in version 1.x may (and should) be removed.

To support multiple framework versions, enable multi-targeting

Where possible and practical, I'd like the libraries in this project to support both netstandard 2 and also the .NET Framework 4.5.

That might not be possible for some of the NHibernate libraries, because I don't think that newer versions of NHibernate support framework 4.5.

This also includes ensuring that - where applicable - tests on CI platforms test both netstandard2.0 and net45 builds of the code.

To ensure the library is working, test coverage should be reviewed

Currently I'm not too sure about the test coverage for the logic in these libraries. Sonar Cube will help a little but I'm particularly concerned about the NHibernate integration.

This needs to be reviewed and checked that everything is tested thoroughly. This includes testing against a real NHibernate environment and also testing that the in-memory implementations offer equivalent functionality.

To simplify the API and integrate with core functionality, rework the transaction-handling to integrate with Transaction Scope

This ticket is to rework the implementation of transactions in this library to integrate with the built-in TransactionScope functionality, as described in this documentation.

This is a standard .NET API which abstracts transaction management away from any specific implementation-related API.

Requirements

The solution to this ticket must support the following:

  • Getting an NHibernate ISession from dependency injection
    • This includes a session which was created before the transaction began
  • Nested transactions (which need to become no-op)

To add support for available APIs, a plan must be devised to support asynchronous database operations

My main ORM of choice (NHibernate) now supports asynchronous operations (unsure which exactly). This ticket is to design an API which will support the usage of that asynchronous
API.

Work to be done

  • Investigate and catalogue the API which NHibernate supports
  • Devise an extension to the ORM API to support the above
  • Create implementations of the API for current versions of NHibernate (including async support)
  • Create implementations of the API for legacy versions of NHibernate (without async support)

Legacy NHibernate support

I plan to support versions of NHibernate back as far as 4.0 with this library. Because of this, I'll have to implement versions of the classes which execute synchronously in order to support NH4.

IdentityValue should not throw if a compatible value is set into the identity

Setting Entity<T>.IdentityValue should not throw an exception is a compatible object is specified for the new identity value.

Example

Currently, the cast from object to TIdentity fails if the entity is Entity<long> but an Int32 is specified as the value. Despite it being possible to cast Int32 to Int64 implicitly under other circumstances, this cast fails.

Desired functionality

If the value is compatible with the identity value type, then it should be gracefully converted. This setter should only throw if the new value cannot be converted.

To avoid developer confusion, the API for comparing entity identities should be simpler

This ticket is to investigate, devise and implement an improvement for the way in which identity instances may be compared for equality.

Current problem

At present, when comparing two instances of IIdentity for equality, the developer is likely to use the equality operator: ==. This is problematic because if the compared variables are presently typed using their interfaces (which is encouraged) then reference equality will be used instead of value equality. Because behind the scenes identity objects are structs, reference equalitywill never be true.

Considerations

Typing identities as interfaces is useful

It is beneficial to type identities as interfaces. This is in order to support generic covariance. If I were to solve this problem by not using interfaces, I would lose the ability to do the following (assuming Cat is a subclass of Animal):

IIdentity<Cat> catId = GetCatId();
IIdentity<Animal> animalId = catId;

Equality operator overloads are incompatible with interfaces

Whilst the variables are typed as interfaces, operator overloads upon the identity type, such as the equality operator, will not be used under any circumstances.

There is some discussion regarding this but I don't see it being implemented any time soon, given that this proposal is already 3 years old.

Unlikely to benefit from using classes instead of structs

Given that the core problem is the mutual exclusivity of covariance (interfaces only) and operator overloading (not interfaces), I doubt that there is a simple solution in swapping from structs to classes for the implementations.

In fact, after some investigation, I am already using classes and not structs for identity objects.

Workaround

As well as being a workaround, this could even be a long-term solution.

Instead of using the equality operator to compare identities, use the static Object.Equals(object, object) method to compare them.

So, instead of this:

identityA == identityB

Use this:

Equals(identityA, identityB)

This will use the overridden Equals methods on the underlying identity objects which will return the correct result.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.