EF vs Nhibernate Merge Disconnected Object Graph

2019-04-30 03:29发布

问题:

I just started a new project a few weeks ago and decided to give EF Code First a try, I used NHIbernate before and i loved the idea of having an ORM out-of-the-bow from MS, and so far it's been great - until i started making complex objects.

My project tiers are as follows: Azure WCF Role - to handle the DAL with EF Code First. Azure WebSite Role with MVC 4 with Knockout - to deal with the client. (I created the WCFRole for the future where we'll need access to the service from different platforms)

Here is the very basic EF Code First design that i'm having trouble with: -I'm transferring only DTOs between the service and site, and made a generic mapper to map inner DTOs if any exist. - I have a City table, and an Address Object with a City Property (we need the City as a property for special functions and not just name)

The client knows the list of Cities, and is returning a new Address with an existing city When i try to add the new Address, a new city is created with the data of the old existing one, I already got that this happens because EF doesn't know how to merge disconnected objects and from what i read doesn't support any merge abitiy, and that the simple not so comfortable solution is just managing the Object State - change the City object state to Unchanged.

But handling this with a big complex db design sounds horrible

my question - What is the best practice/ easy way of handling this? I thought about solutions like - overriding the SaveChanges method going though all objects and if ID is not null/0/some other convention to change it from Added to Unchanged - can this solution be done?

my 2nd question - because i have a lot of experience with NHibernate (with connected objects) - I was wondering what NHibernate's take on this? i read somewhere that NHibernate does have an AutoMagic Merge ability to reconnect disconnected complex objects, is this true? will my basic disconnected Address->City design will work out-of-the-box with that AutoMagic Merge? And what are the ramifications of using that?

Thanks a lot :)

Update: a simplified code for the issue.

public class Address
{
    public int ID { get; set; }

    public virtual City City { get; set; }
}

public class City
{
    public int ID { get; set; }

    public string Name { get; set; }
    public virtual Zone Zone { get; set; }
}

public class MyContext : DbContext
{
    public MyContext() : base("TransportService") { }

    public virtual DbSet<City> Cities { get; set; }
    public virtual DbSet<Address> Addresses { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Address>()
            .HasRequired(x => x.City)
            .WithMany().WillCascadeOnDelete(true);

    }
}

Adding new Address:

    public void Add(AddressDto address)
    {
        using (var context = new MyContext())
        {
            context.Addresses.Add(address.FromDto<Address>());

            context.SaveChanges();
        }
    }

The "FromDto" is the generic Mapper extension, it creates the new address with all the Information, including the City (and the City.ID property)

This will result in creating a new city instead of using a reference to the old city.

回答1:

I found that EF doesn't have auto merge, their merge capabilities so far are only manual merge, and it will work only if the Context object has in memory all the dependencies of the object.

Dealing with multilevel disconnected objects, and dealing with reconnecting them manually is a lot of work and can result in really weird and hard to handle bugs (just like the one stated in the question where new cities where created because it wasn't merged , so it just created a new one even if it had an ID)

so for now - Nhibernate wins this battle, Nhibernate has an automagic merge functionality, if your disconnected object has an ID it will try to merge it, and be successful (from my experience) It's a little more setting up to get things running compared to the EF, but it is worth the trouble.