微风:实体框架和NHibernate之间存在许多差异

时间:2013-12-19 14:22:19

标签: nhibernate breeze

情况如下:

  • WebApi v1
  • Breeze 1.4.7
  • EF 5.0 / NHibernate 3.3.1

我们想要什么:多对多地暴露出来。客户可以有多个国家/地区,一个国家/地区可以有多个客户。已为此目的创建了ClientCountry实体。

我的映射如下所示:

实体框架:

        modelBuilder.Entity<Client>().HasKey(p => p.Id).Property(p=>p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        modelBuilder.Entity<Client>().Property(p => p.Abbreviation);
        modelBuilder.Entity<Client>().Property(p => p.ClientSinceDate).IsRequired();
        modelBuilder.Entity<Client>().Property(p => p.ClientUntilDate);
        modelBuilder.Entity<Client>().Property(p => p.Name).IsRequired();
        modelBuilder.Entity<Client>().Property(p => p.Website);
        modelBuilder.Entity<Client>().HasMany(p => p.Contacts).WithRequired(p => p.Client).WillCascadeOnDelete(true);
        modelBuilder.Entity<Client>().HasMany(p => p.ClientCountries).WithRequired(p => p.Client).WillCascadeOnDelete(true);

        modelBuilder.Entity<Contact>().HasKey(p => p.Id).Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        modelBuilder.Entity<Contact>().Property(p => p.Username);
        modelBuilder.Entity<Contact>().HasRequired(p => p.Client);

        modelBuilder.Entity<Country>().HasKey(p => p.Id).Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 
        modelBuilder.Entity<Country>().Property(p => p.ValidFrom);
        modelBuilder.Entity<Country>().Property(p => p.ValidTo);
        modelBuilder.Entity<Country>().Property(p => p.Code);
        modelBuilder.Entity<Country>().Property(p => p.DefaultLabel);
        modelBuilder.Entity<Country>().Property(p => p.Description);
        modelBuilder.Entity<Country>().Property(p => p.DisplayOrder);

        modelBuilder.Entity<ClientCountry>().HasKey(p => p.Id).Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 
        modelBuilder.Entity<ClientCountry>().Property(p => p.ValidFrom);
        modelBuilder.Entity<ClientCountry>().Property(p => p.ValidTo);
        modelBuilder.Entity<ClientCountry>().HasRequired(p => p.Client);
        modelBuilder.Entity<ClientCountry>().HasRequired(p => p.Country);

NHibernate的:

public class BaseMapping<T> : ClassMapping<T> where T : BaseEntity
{
    public BaseMapping()
    {
        this.Lazy(true);
        Id(x => x.Id, map => { map.Generator(Generators.GuidComb); });
    }
}

public class ClientMap : BaseMapping<Client>
{
    public ClientMap()
    {
        this.Property(x => x.Name);
        this.Property(x => x.Abbreviation);
        this.Property(x => x.ClientSinceDate, map => map.NotNullable(true));
        this.Property(x => x.ClientUntilDate);
        this.Property(x => x.City);
        this.Property(x => x.Website);

        this.Bag<Department>(x => x.Departments, colmap =>
        {
            colmap.Key(x => x.Column("ClientId"));
            colmap.Inverse(true);
            colmap.Cascade(Cascade.All | Cascade.DeleteOrphans);
        }, map =>
        {
            map.OneToMany();
        });

        this.Bag<ClientCountry>(x => x.ClientCountries, colmap =>
        {
            colmap.Cascade(Cascade.All | Cascade.DeleteOrphans);
            colmap.Key(p => p.Column("ClientId"));
            colmap.Inverse(true);
        }, map =>
        { 
            map.OneToMany();
        });

        this.Bag<Contact>(x => x.Contacts, colmap =>
        {
            colmap.Key(x => x.Column("ClientId"));
            colmap.Cascade(Cascade.All | Cascade.DeleteOrphans);
        }, map =>
        {
            map.OneToMany();
        });
    }
}

public class CountryMap : BusinessRefEntityMapping<Country>
{
    public CountryMap()
    {
        Bag<ClientCountry>(x => x.ClientCountries, colmap =>
        {
            colmap.Cascade(Cascade.All);
            colmap.Key(p => p.Column("CountryId"));
        }, map =>
        {
            map.OneToMany();
        });
    }
}

public class ClientCountryMap : BaseMapping<ClientCountry>
{
    public ClientCountryMap()
    {
        Property(x => x.ValidFrom);
        Property(x => x.ValidTo);

        Property(x => x.ClientId, map =>
        {
            map.Column("ClientId");
            map.Insert(false);
            map.Update(false);
            map.NotNullable(true);
        });
        Property(x => x.CountryId, map =>
        {
            map.Column("CountryId");
            map.Insert(false);
            map.Update(false);
            map.NotNullable(true);
        });

        ManyToOne<Client>(x => x.Client, map =>
        {
            map.Column("ClientId");
            map.Cascade(Cascade.All);
            map.Insert(true);
            map.Update(true);
            map.NotNullable(true);
        });

        ManyToOne<Country>(x => x.Country, map =>
        {
            map.Column("CountryId");
            map.Cascade(Cascade.All);
            map.Insert(true);
            map.Update(true);
            map.NotNullable(true);
        });
    }
}

js代码:

 $scope.create = function (index) {

    var c = $scope.clients[index];

    var newClientCountry = breezeService.manager.createEntity('ClientCountry', {
        ValidFrom: Date(2013, 01, 01),
        ValidTo: Date(2015, 01, 01),
        Client: c,
        Country: country,
    });


    breezeService.manager.saveChanges()
    .then(function (data) {
        $log.info('client created');
    })
    .fail(function (dat) {
        $log.error('save client failed:' + data)
    })
}

问题:使用NHibernate时,保存clientcountry会导致出现此错误消息:“not-null属性引用空值或瞬态值CdT.EAI.DAL.ClientCountry.Country”。使用EF,所有工作都按预期进行。

我的代码有问题吗?

1 个答案:

答案 0 :(得分:0)

所以,既然目前还没有任何反馈意见,那么我们采取的措施(或多或少)也是如此:

  • 首先,为了能够保存一个新的ClientCountry(暴露的联结表中多对多),我们必须这样做:

    public class ClientCountryMap : BaseMapping<ClientCountry>
    {
        public ClientCountryMap()
        {
            Property(x => x.ValidFrom);
            Property(x => x.ValidTo);
            Property(x => x.ClientId, map =>
            {
                map.Column("ClientId");
                map.Insert(true);
                map.Update(true);
                map.NotNullable(true);
            });
            Property(x => x.CountryId, map =>
            {
                map.Column("CountryId");
                map.Insert(true);
                map.Update(true);
                map.NotNullable(true);
            });
            ManyToOne<Client>(x => x.Client, map =>
            {
                map.Column("ClientId");
                map.Cascade(Cascade.All);
                map.Insert(false);
                map.Update(false);
                map.NotNullable(true);
            });
            ManyToOne<Country>(x => x.Country, map =>
            {
                map.Column("CountryId");
                map.Cascade(Cascade.All);
                map.Insert(false);
                map.Update(false);
                map.NotNullable(true);
            });
        }
    }
    

    这里的区别在于插入/更新是反转的。必须在外键映射上设置Insert(true)Update(true),而不是关联。它与breeze doc的不同之处在于。

  • 第二个是必须在每个集合关联上设置Inverse(true),否则在更新父实体时将删除所有集合。

有了这些,变化,它似乎按预期工作。

ps:它已在最新版本(&gt; 1.4.8)中修复。以上评论不再适用。