我想爲我的一些實體創建一個基類,因爲它們都共享一個Event
列表屬性。 我也想使Event
列表只讀屬性。流利NHibernate正確地將只讀屬性映射到基類
所以我創建了一個基類EventRelatedEntity
類,然後在每個與事件有關的實體類中派生它。
請注意,EventRelatedEntity
類沒有NHibernate映射類,因爲它沒有鏈接到表。
查看下面的代碼。
基類:
public class EventRelatedEntity
{
private readonly List<Event> events;
public virtual IReadOnlyCollection<Event> Events { get; protected set; }
public EventRelatedEntity()
{
events = new List<Event>();
Events = events.AsReadOnly();
}
protected virtual void AddEvent<T>(T entity, string message)
{
if (events == null)
events = new List<Event>();
Event newEvent = new Event();
if (typeof(T) == typeof(Company))
{
newEvent.CompanyId = (entity as Company).Id;
// ...and do some other stuff...
}
else if (typeof(T) == typeof(Document))
{
newEvent.DocumentId = (entity as Document).Id;
// ...and do some other stuff...
}
else if (typeof(T) == typeof(Typology))
{
newEvent.TypologyId = (entity as Typology).Id;
// ...and do some other stuff...
}
newEvent.Message = message;
events.Add(newEvent);
}
}
實體類
public class Company : EventRelatedEntity
{
[Key]
public virtual int Id { get; protected set; }
[Required]
public virtual string Alias { get; set; }
[Required]
public virtual string CompanyName { get; set; }
// ...and some other properties...
#region Actions
public virtual void AddEvent(string message)
{
base.AddEvent(this, message);
}
#endregion
}
public class Document : EventRelatedEntity
{
[Key]
public override int Id { get; protected set; }
[Required]
public virtual User User { get; protected set; }
// ...and some other properties...
#region Actions
public virtual void AddEvent(string message)
{
base.AddEvent(this, message);
}
#endregion
}
// ...and some other classes...
功能NHibernate映射類爲實體
public class CompanyMap : ClassMap<Company>
{
public CompanyMap()
{
Table("Companies");
LazyLoad();
Id(x => x.Id).GeneratedBy.Identity().Column("Id");
Map(x => x.Alias).Column("Alias").Not.Nullable();
Map(x => x.CompanyName).Column("CompanyName").Not.Nullable();
// ...and some other mappings...
// Link with Events table
HasMany(x => x.Events) // Events is declared in the base class (EventRelatedEntity)
.KeyColumn("CompanyId")
.Access.LowerCaseField()
.Cascade.AllDeleteOrphan();
}
}
public class DocumentMap : ClassMap<Document>
{
public DocumentMap()
{
Table("Documents");
LazyLoad();
Id(x => x.Id).GeneratedBy.Identity().Column("Id");
References(x => x.User).Column("UserId");
// ...and some other mappings...
// Link with Events table
HasMany(x => x.Events) // Events is declared in the base class (EventRelatedEntity)
.KeyColumn("DocumentId")
.Access.LowerCaseField()
.Cascade.AllDeleteOrphan();
}
}
// ...and some other mapping classes...
最後我想避免直接訪問List<>.Add()
方法。我想要一個只讀集合。將新的Event
添加到實體的事件列表的唯一方法必須是相應實體類的AddEvent
方法。
例子:
Document document = session.Get<Document>(1);
// ...the same for other derived classes...
// I WANT TO AVOID THIS!
document.Events.Add(new Event());
// WANTS TO BE THE ONLY PERMITTED WAY TO ADD NEW EVENTS
document.AddEvent("My new event message");
的問題是,當我做:
Document document = session.Get<Document>(1);
我從NHibernate的一個錯誤:
Cannot cast objects of type 'NHibernate.Collection.Generic.PersistentGenericBag'1 [SolutionDOC_Interface.Entity.Event]' to the 'System.Collections.Generic.List'1 [SolutionDOC_Interface.Entity.Event]' type.
,我認爲它是與相關實際上EventRelatedEntity
類沒有NHibernate映射,但我無法提供映射,因爲它沒有d o用DB中的表格。 也許如果我在每個類(公司,文檔等)內部聲明事件列表而不使用繼承,NHibernate就可以工作,但是這種方法會產生很多我想避免的代碼重複。
UPDATE 2017/10/18
改變這樣的代碼@ryan建議後,現在它的工作原理。
修改後的代碼:
public class EventRelatedEntity
{
private readonly IList<Event> events;
public virtual IReadOnlyCollection<Event> Events { get; protected set; }
public EventRelatedEntity()
{
events = new List<Event>();
Events = (events as List<Event>).AsReadOnly();
}
// ...
}
有啥問題?如果'Events'確實被聲明爲'IReadOnlyCollection',那麼'document.Events.Add(new Event());'應該產生一個錯誤:''IReadOnlyCollection''不包含'Add'的定義。 。' –
ryan
我得到一個NHibernate錯誤。我更新了這個問題。 –