Breeze:实体框架和NHibernate的多对多差异

Breeze:实体框架和NHibernate的多对多差异,nhibernate,breeze,Nhibernate,Breeze,情况如下: WebApi v1 微风1.4.7 EF 5.0/NHibernate 3.3.1 我们想要的是:多对多暴露为多对一。一个客户可以有多个国家,一个国家可以有多个客户。已为此目的创建了ClientCountry实体 我的映射如下所示: 实体框架: modelBuilder.Entity<Client>().HasKey(p => p.Id).Property(p=>p.Id).HasDatabaseGeneratedOption(Databa

情况如下:

  • WebApi v1
  • 微风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,保存clientcountry会导致以下错误消息:“NOTNULL属性引用空值或暂时值CdT.EAI.DAL.clientcountry.Country”。有了EF,一切都按预期进行


我的代码有问题吗

因此,由于还没有反馈,我们采取了以下措施使其(或多或少)发挥作用:

  • 首先,为了能够保存一个新的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);
            });
        }
    }
    
    公共类ClientCountryMap:BaseMapping
    {
    公共客户端CountryMap()
    {
    属性(x=>x.ValidFrom);
    属性(x=>x.ValidTo);
    属性(x=>x.ClientId,map=>
    {
    地图栏(“客户ID”);
    map.Insert(true);
    地图更新(真);
    map.NotNullable(true);
    });
    属性(x=>x.CountryId,map=>
    {
    地图栏(“CountryId”);
    map.Insert(true);
    地图更新(真);
    map.NotNullable(true);
    });
    多通(x=>x.客户端,映射=>
    {
    地图栏(“客户ID”);
    map.Cascade(Cascade.All);
    地图。插入(假);
    地图更新(假);
    map.NotNullable(true);
    });
    多通(x=>x.国家,地图=>
    {
    地图栏(“CountryId”);
    map.Cascade(Cascade.All);
    地图。插入(假);
    地图更新(假);
    map.NotNullable(true);
    });
    }
    }
    
    这里的区别在于插入/更新是反向的<代码>插入(true)和
    更新(true)
    必须在外键映射上设置,而不是在关联上设置。在这一点上,它与以前的观点不同

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

有了这些变化,它似乎像预期的那样工作

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

 $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)
    })
}
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);
        });
    }
}