C# 如何使用FluentNhibernate将集合配置为非只读?

C# 如何使用FluentNhibernate将集合配置为非只读?,c#,fluent-nhibernate,fluent-nhibernate-mapping,readonly-collection,C#,Fluent Nhibernate,Fluent Nhibernate Mapping,Readonly Collection,我已经尝试了我能想到的一切,我只是卡住了。我有一个用户,它有许多邀请,但是当我试图通过调用AddInvitation()将邀请添加到用户的邀请字段时,会抛出一个不受支持的异常,因为集合是只读的。我觉得这是映射覆盖中的一个问题,但是我有很多其他类/关系遵循相同的模式,而且(到目前为止)我在其他地方没有发现这个问题。为什么备份字段是只读的,我应该如何防止备份字段变成只读的 User.cs public class User { private IList<Invitation> in

我已经尝试了我能想到的一切,我只是卡住了。我有一个
用户
,它有许多
邀请
,但是当我试图通过调用
AddInvitation()
邀请
添加到
用户
邀请
字段时,会抛出一个
不受支持的
异常,因为
集合是只读的
。我觉得这是映射覆盖中的一个问题,但是我有很多其他类/关系遵循相同的模式,而且(到目前为止)我在其他地方没有发现这个问题。为什么备份字段是只读的,我应该如何防止备份字段变成只读的

User.cs

public class User
{
  private IList<Invitation> invitations = new List<Invitation>();

  public virtual IEnumerable<Invitation> Invitations
  {
    get { return new ReadOnlyCollection<Invitation>(this.invitations);
  }

  public virtual User AddInvitation(Invitation invitation)
  {
    if (!this.invitations.Contains(invitation))
    {
      this.invitations.Add(invitation); // <-- throws System.NotSupportedException: Collection is read-only.
    }

    return this;
  }
}
Database.cs

public class Database
{
  // code removed for brevity
  private static void MapAssemblies(FluentNHibernate.Cfg.MappingConfiguration config)
  {
    config.AutoMappings.Add(
      AutoMap.Assembly(Assembly.GetAssembly(typeof(User)))
      .Override<User>(userMapping =>
      {
        userMapping.HasMany<Invitation>(userType => userType.Invitations)
        .Not.LazyLoad()
        .Inverse()
        .Cascade.SaveUpdate()
        .KeyColumn("User_id");
      })
      .Override<Invitation>(invitationMapping =>
      {
        invitationMapping.References<User>(invitationType => invitationType.Sender)
        .Column("User_id");
      });
    );
  }
  // code removed for brevity
}
公共类数据库
{
//为简洁起见,删除了代码
私有静态void映射程序集(FluentNHibernate.Cfg.MappingConfiguration配置)
{
config.AutoMappings.Add(
AutoMap.Assembly(Assembly.GetAssembly(typeof(User)))
.Override(userMapping=>
{
userMapping.HasMany(userType=>userType.investments)
.Not.LazyLoad()
.Inverse()
.Cascade.SaveUpdate()
.KeyColumn(“用户id”);
})
.Override(invitationMapping=>
{
invitationMapping.References(invitationType=>invitationType.Sender)
.列(“用户id”);
});
);
}
//为简洁起见,删除了代码
}
经理

public class Manager
{
  private ISession session = null; // initialised in .ctor

  // code removed for brevity
  public void AddInvitation(/*parameters removed*/)
  {
    User user = this.session.Get<User>(identifier);
    Invitation invitation = new Invitation().From(user);
    user.AddInvitation(invitation);
    using (ITransaction transaction = this.session.BeginTransaction())
    {
      this.session.SaveOrUpdate(invitation);
      transaction.Commit();
    }
  }
  // code removed for brevity
}
公共类管理器
{
private ISession session=null;//在.ctor中初始化
//为简洁起见,删除了代码
公共无效添加提示(/*参数已删除*/)
{
User=this.session.Get(标识符);
邀请=来自(用户)的新邀请();
用户。添加邀请(邀请);
使用(ITransaction transaction=this.session.BeginTransaction())
{
此.session.SaveOrUpdate(邀请);
Commit();
}
}
//为简洁起见,删除了代码
}
我得到了实际的异常消息(最初应该添加此消息)

在System.ThrowHelper.ThrownNotSupportedException(例外资源) 位于System.Collections.ObjectModel.ReadOnlyCollection'1.System.Collections.Generic.ICollection.Add(T值) 位于NHibernate.Collection.Generic.PersistentGenericBag'1.System.Collections.Generic.icCollection.Add(T项)


看起来,即使我在修改字段邀请,访问者邀请添加的ReadOnlyCollection包装器也在修改字段本身。

我认为问题来自ReadOnlyCollection,您为什么要将邀请初始化为只读集合

在映射过程中,您正在将数据填充到邀请只读集合中,并且可能您的邀请字段初始化为列表被只读集合隐藏


当您想访问邀请时,也许不要每次都重新初始化邀请集合,而只返回邀请字段,您可以将此字段设置为只读。

我认为问题来自ReadOnlyCollection,您为什么要将邀请初始化为只读集合

在映射过程中,您正在将数据填充到邀请只读集合中,并且可能您的邀请字段初始化为列表被只读集合隐藏


当您想访问邀请时,请不要每次都重新初始化邀请集合,只返回邀请字段,您可以将此字段设置为只读。

旧问题,实际问题!而且,在保持收藏为只读的情况下进行修复并不难:

    userMapping.HasMany<Invitation>(userType => userType.Invitations)
    .Not.LazyLoad()
    .Inverse()
    .Access.CamelCaseField() // this does the trick!
    .Cascade.SaveUpdate()
    .KeyColumn("User_id");
userMapping.HasMany(userType=>userType.investments)
.Not.LazyLoad()
.Inverse()
.Access.CamelCaseField()//这就成功了!
.Cascade.SaveUpdate()
.KeyColumn(“用户id”);

如果NHibernate通过backing字段访问集合,它不知道它是只读的,因此它将实例化一个读写集合。公共界面仍然是只读的。

老问题,实际问题!而且,在保持收藏为只读的情况下进行修复并不难:

    userMapping.HasMany<Invitation>(userType => userType.Invitations)
    .Not.LazyLoad()
    .Inverse()
    .Access.CamelCaseField() // this does the trick!
    .Cascade.SaveUpdate()
    .KeyColumn("User_id");
userMapping.HasMany(userType=>userType.investments)
.Not.LazyLoad()
.Inverse()
.Access.CamelCaseField()//这就成功了!
.Cascade.SaveUpdate()
.KeyColumn(“用户id”);

如果NHibernate通过backing字段访问集合,它不知道它是只读的,因此它将实例化一个读写集合。公共接口仍然是只读的。

将邀请公开为只读的原因是,任何客户端代码都无法更改邀请-客户端代码必须调用AddInvitation。当调用邀请的getter时,它不会重新初始化,新的ReadOnlyCollection(IList items)应该只在项目周围放置一个包装器,尽管我认为在这种情况下,项目实际上正在被修改……好的,这个问题完全取决于ReadOnlyCollection包装器,如果删除,集合将不再是只读的。C#library中的大多数实现似乎会生成一个新数组,并在用户请求时创建数据副本。这使得客户机代码在不损害原始数据的情况下具有所需的破坏性。即使您使用ReadOnlyCollection,我听说有一些巧妙的方法可以使其可变-它应该用于显示意图而不是安全性。公开将邀请公开为只读的原因是,它不能被任何客户端代码更改-客户端代码必须调用AddInvitation。当调用邀请的getter时,它不会重新初始化,新的ReadOnlyCollection(IList items)应该只在项目周围放置一个包装器,尽管我认为在这种情况下,项目实际上正在被修改……好的,这个问题完全取决于ReadOnlyCollection包装器,如果删除,集合将不再是只读的。C#library中的大多数实现似乎会生成一个新数组并创建数据的副本