C# Fluent NHibernate:如何在关系表上映射具有附加属性的多对多关系?

C# Fluent NHibernate:如何在关系表上映射具有附加属性的多对多关系?,c#,nhibernate,orm,fluent-nhibernate,nhibernate-mapping,C#,Nhibernate,Orm,Fluent Nhibernate,Nhibernate Mapping,我正在尝试映射两个实体之间的多对多关系,但我需要用许多属性装饰该实体-请参见下图: Reads在本例中是我的关系表-我在其上添加了一个标识列,以避免使用复合键,但这里有价值的信息实际上是UserId、FeedItemId和TimeRead属性。根据我在StackOverFlow上看到的类似示例,下面是我如何尝试映射这种关系的: 用户 public class UserMap : ClassMap<User> { public UserMap() {

我正在尝试映射两个实体之间的多对多关系,但我需要用许多属性装饰该实体-请参见下图:

Reads在本例中是我的关系表-我在其上添加了一个标识列,以避免使用复合键,但这里有价值的信息实际上是UserId、FeedItemId和TimeRead属性。根据我在StackOverFlow上看到的类似示例,下面是我如何尝试映射这种关系的:

用户

public class UserMap : ClassMap<User>
{
    public UserMap()
    {
        Id(x => x.UserId).GeneratedBy.Identity();
        Map(x => x.UserName).Length(DataConstants.UserNameLength).Unique().Not.Nullable();
        Map(x => x.EmailAddress).Length(DataConstants.EmailAddressLength).Unique().Not.Nullable();
        Map(x => x.DateJoined).Not.Nullable();
        Map(x => x.Password).Length(DataConstants.PasswordHashLength).Not.Nullable();
        HasManyToMany(x => x.UserRoles).Cascade.AllDeleteOrphan().AsBag().Table("UsersInRole");
        HasManyToMany(x => x.SubscribedFeeds).Cascade.DeleteOrphan().AsBag().Table("Subscriptions");
        HasManyToMany(x => x.OwnedFeeds).Cascade.All().AsBag().Table("FeedOwners");
        HasMany(x => x.Reads).Cascade.DeleteOrphan().Fetch.Join().Inverse().KeyColumn("UserId");
    }
}
这可能是因为,用户和FeedItem在关系映射上都有一个.Inverse,我这样做是因为我在大多数其他示例中看到了试图对同一关系建模的东西

当我从用户映射中删除.Inverse时,会出现以下错误:

NHibernate.TransientObject异常: 对象引用未保存的瞬态 实例-保存临时实例 冲洗前

我的最终目标是能够执行Session.SaveOrUpdate(user),并让它将任何新的提要读取直接插入到reads表中,但我还没有找到一种方法来执行。我做错了什么


关于StackOverFlow这个主题,我已经阅读了几乎所有其他的问题,但还没有找到一个明确的答案。

这取决于你想如何保存新的阅读

若要通过用户保存新的读取,则需要用户的Cacascade.AllDeleteOrphan()。目前,它不会级联新的读取,因为您只有DeleteOrphan

public class UserMap : ClassMap<User>
{
    public UserMap()
    {
        Id(x => x.UserId).GeneratedBy.Identity();
        Map(x => x.UserName).Length(DataConstants.UserNameLength).Unique().Not.Nullable();
        Map(x => x.EmailAddress).Length(DataConstants.EmailAddressLength).Unique().Not.Nullable();
        Map(x => x.DateJoined).Not.Nullable();
        Map(x => x.Password).Length(DataConstants.PasswordHashLength).Not.Nullable();
        HasManyToMany(x => x.UserRoles).Cascade.AllDeleteOrphan().AsBag().Table("UsersInRole");
        HasManyToMany(x => x.SubscribedFeeds).Cascade.DeleteOrphan().AsBag().Table("Subscriptions");
        HasManyToMany(x => x.OwnedFeeds).Cascade.All().AsBag().Table("FeedOwners");
        HasMany(x => x.Reads).Cascade.AllDeleteOrphan().Fetch.Join().Inverse().KeyColumn("UserId");
    }
}
公共类用户映射:类映射
{
公共用户映射()
{
Id(x=>x.UserId).GeneratedBy.Identity();
Map(x=>x.UserName).Length(DataConstants.UserNameLength).Unique().Not.Nullable();
Map(x=>x.EmailAddress).Length(DataConstants.EmailAddressLength).Unique().Not.Nullable();
Map(x=>x.DateJoined).Not.Nullable();
Map(x=>x.Password).Length(DataConstants.PasswordHashLength).Not.Nullable();
HasManyToMany(x=>x.UserRoles).Cascade.AllDeleteOrphan().AsBag().Table(“UsersInRole”);
HasManyToMany(x=>x.SubscribedFeeds).Cascade.DeleteOrphan().AsBag().Table(“订阅”);
HasManyToMany(x=>x.OwnedFeeds).Cascade.All().AsBag().Table(“FeedOwners”);
HasMany(x=>x.Reads).Cascade.AllDeleteOrphan().Fetch.Join().Inverse().KeyColumn(“用户ID”);
}
}

只是一个想法,我总是喜欢尽量减少双向关系,以保持域更简单。因此,如果可以避免的话,我可能不会在User或FeedItem上收集这些内容。

Ugh,我太傻了-我以为我已经将其设置为Cascade.AllDeleteOrphan-谢谢你指出我的错误!
public class FeedReadMap : ClassMap<FeedRead>
{
    public FeedReadMap()
    {
        Table("Reads");
        //CompositeId()
        //    .KeyProperty(x => x.TimeRead, "TimeRead")
        //    .KeyReference(x => x.ItemRead, "FeedItemId")
        //    .KeyReference(x => x.Reader, "UserId");
        Id(x => x.ReadId).GeneratedBy.Identity();
        Map(x => x.TimeRead).Not.Nullable();
        References(x => x.Reader).Not.Nullable().Cascade.SaveUpdate().Column("UserId");
        References(x => x.ItemRead).Not.Nullable().Cascade.SaveUpdate().Column("FeedItemId");
    }
}
var read = new FeedRead {ItemRead = feed.Items[0], Reader = user, TimeRead = DateTime.Now};
        user.Reads.Add(read);
        feed.Items[0].Reads.Add(read);

        _repository.SaveUser(user);
public class UserMap : ClassMap<User>
{
    public UserMap()
    {
        Id(x => x.UserId).GeneratedBy.Identity();
        Map(x => x.UserName).Length(DataConstants.UserNameLength).Unique().Not.Nullable();
        Map(x => x.EmailAddress).Length(DataConstants.EmailAddressLength).Unique().Not.Nullable();
        Map(x => x.DateJoined).Not.Nullable();
        Map(x => x.Password).Length(DataConstants.PasswordHashLength).Not.Nullable();
        HasManyToMany(x => x.UserRoles).Cascade.AllDeleteOrphan().AsBag().Table("UsersInRole");
        HasManyToMany(x => x.SubscribedFeeds).Cascade.DeleteOrphan().AsBag().Table("Subscriptions");
        HasManyToMany(x => x.OwnedFeeds).Cascade.All().AsBag().Table("FeedOwners");
        HasMany(x => x.Reads).Cascade.AllDeleteOrphan().Fetch.Join().Inverse().KeyColumn("UserId");
    }
}