[英]Linq to SQL Generic Repository Pattern Update Issue
I have a weird problem. 我有一个奇怪的问题。 I am using Generic Repository pattern and Linq to SQL. 我正在使用通用存储库模式和SQL的Linq。 I have many to many relations between objects which are dbml generated objects and here is the problem. 我是dbml生成的对象之间的对象之间有很多关系,这就是问题所在。 I am getting an error when I try to update the Player object. 尝试更新Player对象时出现错误。 The error occures when I try to update name of player's skill. 当我尝试更新玩家技能名称时,会发生错误。 This is the exception I'm getting: 这是我得到的例外:
An exception of type 'System.InvalidOperationException' occurred in System.Data.Linq.dll but was not handled in user code System.Data.Linq.dll中发生类型'System.InvalidOperationException'的异常,但未在用户代码中处理
Additional information: An attempt was made to remove a relationship between a Skill and a PlayerSkill. 附加信息:试图删除技能和玩家技能之间的关系。 However, one of the relationship's foreign keys (PlayerSkill.Skill_ID) cannot be set to null. 但是,关系的外键之一(PlayerSkill.Skill_ID)不能设置为null。
Here is the Update method. 这是Update方法。
public void Update(PlayerEntity player)
{
Player p = Mapper.Map<PlayerEntity, Player>(player);
_unitOfWork.SkillRepository.AddOrUpdate(p.PlayerSkills.Select(i => i.Skill).ToList());
_unitOfWork.ProfileRepository.AddOrUpdate(p.Profile);
_unitOfWork.SocialAccountRepository.AddOrUpdate(p.SocialAccount);
_unitOfWork.PlayerRepository.AddOrUpdate(p);
}
AddOrUpdate method on repo: 回购上的AddOrUpdate方法:
public void AddOrUpdate(ICollection<TEntity> entities)
{
foreach (var e in entities)
{
AddOrUpdate(e);
}
}
public void AddOrUpdate(TEntity entity)
{
if (GetPrimaryKeyValue(entity) > 0)
{
Update(entity);
}
else
{
Insert(entity);
}
}
Update method on DataLINQ layer DataLINQ层上的更新方法
public void Update(TEntity entity)
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
var original = GetById(GetPrimaryKeyValue(entity));
ApplyChanges(original, entity);
_context.SubmitChanges();
}
Lastly; 最后; ApplyChanges 应用更改
private void ApplyChanges<F, S>(F originalEntity, S newEntity)
{
var entityType = typeof(F);
var entityProperties = entityType.GetProperties();
foreach (var propertyInfo in entityProperties)
{
var currentProperty = entityType.GetProperty(propertyInfo.Name);
currentProperty.SetValue(originalEntity, propertyInfo.GetValue(newEntity, null));
}
}
I call the object as follows: 我将对象称为如下:
public IHttpActionResult PutPlayer(int id, PlayerEntity player)
{
if (player == null)
{
return NotFound();
}
_playerService.Update(player);
return Ok();
}
Note: I use AutoMapper to map the objects, but I don't think that is related with error. 注意:我使用AutoMapper来映射对象,但是我认为这与错误无关。 Thanks in adv. 感谢在广告中。
The problem is that your method ApplyChanges
copies too many properties. 问题在于您的方法ApplyChanges
复制了太多的属性。 You want it to copy scalar properties only, ie properties of type int
, string
, etc., not references and collections. 您只希望它复制标量属性,即int
, string
等类型的属性,而不是引用和集合。 But your method does all of them. 但是您的方法可以完成所有这些操作。
This causes LINQ-to-SQL to conclude that PlayerSkills
is replaced by a brand new collection of PlayerSkill
objects. 这使LINQ-to-SQL得出结论,即PlayerSkills
被全新的PlayerSkill
对象集合PlayerSkill
。 So it will try to insert new ones. 因此它将尝试插入新的。 But it will also try to orphan the existing ones. 但是它也会尝试孤立现有的。 That causes the exception that PlayerSkill.Skill_ID
can't be set to null. 这导致无法将PlayerSkill.Skill_ID
设置为null的异常。
The solution is to copy scalar properties only: 解决方案是仅复制标量属性:
private void ApplyChanges<F, S>(F originalEntity, S newEntity)
{
var entityType = typeof(F);
var entityProperties = entityType.GetProperties();
foreach (var propertyInfo in entityProperties
// Filter scalar properties
.Where(pi => pi.PropertyType.IsValueType || pi.PropertyType == typeof(string)))
{
var currentProperty = entityType.GetProperty(propertyInfo.Name);
currentProperty.SetValue(originalEntity, propertyInfo.GetValue(newEntity, null));
}
}
This filters value-type properties and string properties(string is not a value type but a class). 这将过滤值类型属性和字符串属性(字符串不是值类型,而是一个类)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.