leo*_*ora 11 c# nhibernate fluent-nhibernate cascading-deletes
我的数据库中有3个表:
如您所见,ProjectsTags表是一个桥表
这是我流利的nhibernate映射
ProjectMap.cs:
Map(x => x.Name).Not.Nullable();
HasMany(x => x.ProjectsTags).AsBag().Inverse()
.Cascade.AllDeleteOrphan().Fetch.Select().BatchSize(80);
Run Code Online (Sandbox Code Playgroud)
ProjectsTagsMap.cs:
References(x => x.Project).Not.Nullable();
References(x => x.Tag).Not.Nullable();
Run Code Online (Sandbox Code Playgroud)
TagMap.cs:
Map(x => x.Name).Not.Nullable();
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,我历史上没有将Tag表链接到其他任何内容.我现在需要生成一个报告来显示Tag以及该标签的使用频率,因此我需要从Tag加入ProjectsTag.我尝试将此行添加到tagsmap中:
HasMany(x => x.ProjectsTags).AsBag().Inverse()
.Cascade.AllDeleteOrphan().Fetch.Select().BatchSize(80);
Run Code Online (Sandbox Code Playgroud)
但是当我去更新标签对象上的名称并提交时,我收到此错误:
拥有实体实例不再引用具有cascade ="all-delete-orphan"的集合
任何人都可以看到我添加的内容有什么问题,当我只是更新Tag表时会导致这个nhibernate异常.我的目标再次是能够做到这样的事情:
Tag.ProjectTags.Count();
Run Code Online (Sandbox Code Playgroud)
以下是一些额外的代码:
我的标签类:
public class Tag
{
public virtual IList<ProjectTag> ProjectTags { get; set; }
public virtual string Name { get; set; }
public virtual string Description { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
Ser*_*gel 19
在代码的某处,您应该取消引用Project域上的原始集合.我怀疑你的代码是这样的:
var project = Session.Get<Project>();
project.ProjectsTags = new List<ProjectsTags> { someProjectsTagsInstance };
Session.Save(project);
Run Code Online (Sandbox Code Playgroud)
如果是这种情况,您应该这样做:
var project = Session.Get<Project>();
project.ProjectsTags.Clear();
project.ProjectsTags.Add(someProjectsTagsInstance);
Session.Save(project);
Run Code Online (Sandbox Code Playgroud)
虽然不修改集合,但NH仍然可以认为它是.这样的事情可能是由鬼更新引起的.来自NHibernate 3.0 Cookbook,Jason Dentler(第184页):"作为自动脏检查的一部分,NHibernate将实体的原始状态与其当前状态进行比较.否则未更改的实体可能会被不必要地更新,因为类型转换导致此比较失败".
集合的Ghost更新可能是由如下代码引起的:
public class Tag
{
private IList<ProjectTag> projectsTags;
public virtual IEnumerable<ProjectTag> ProjectsTags
{
get
{
return new ReadOnlyCollection<ProjectTag>(projectsTags);
}
set
{
projectsTags = (IList<ProjectTag>)value;
}
}
}
Run Code Online (Sandbox Code Playgroud)
ProjectsTags属性在readonly包装器中返回集合,因此客户端代码无法在集合中添加或删除元素.
即使标签名称未更改,也会出现错误:
private void GhostTagUpdate(int id)
{
using (var session = OpenSession())
{
using (var transaction = session.BeginTransaction())
{
var tag = session.Get<Tag>(id);
transaction.Commit();
}
}
}
Run Code Online (Sandbox Code Playgroud)
ProjectsTags集合应与CamelCaseField访问策略一起映射,以避免ghost更新:
HasMany(x => x.ProjectsTags)
.Access.CamelCaseField()
.AsBag().Inverse().Cascade.AllDeleteOrphan().Fetch.Select().BatchSize(80);
Run Code Online (Sandbox Code Playgroud)
无论如何...
你的关联似乎是恶魔般的复杂.如果ProjectsTags表应该只包含tag的id和项目的id,那么使用FNH多对多双向映射会更简单:
public class Tag2Map : ClassMap<Tag2>
{
public Tag2Map()
{
Id(x => x.Id);
Map(x => x.Name);
HasManyToMany(x => x.Projects)
.AsBag()
.Cascade.None()
.Table("ProjectsTags")
.ParentKeyColumn("TagId")
.ChildKeyColumn("ProjectId");
}
}
public class Project2Map : ClassMap<Project2>
{
public Project2Map()
{
Id(x => x.Id);
Map(x => x.Name);
HasManyToMany(x => x.Tags)
.AsBag()
.Cascade.None()
.Inverse()
.Table("ProjectsTags")
.ParentKeyColumn("ProjectId")
.ChildKeyColumn("TagId");
}
}
Run Code Online (Sandbox Code Playgroud)
现在模型中不需要ProjectTag实体.可以通过两种方式检索给定标签使用次数的计数:
直接方式:tag.Projects.Count()- 但它从数据库中检索所有项目.
查询方式:
var tag = session.Get<Tag2>(tagId);
var count = session.Query<Project2>().Where(x => x.Tags.Contains(tag)).Count();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6915 次 |
| 最近记录: |