显然,EF6不喜欢具有多个使用相同键值的外键属性但不共享相同引用的对象。例如:
var user1 = new AppUser { Id = 1 };
var user2 = new AppUser { Id = 1 };
var address = new Address
{
CreatedBy = user1, //different reference
ModifiedBy = user2 //different reference
};
当我尝试插入此记录时,EF会抛出此异常:
Saving or accepting changes failed because more than one entity of type
'AppUser' have the same primary key value. [blah blah blah]
我发现这样做可以解决问题:
var user1 = new AppUser { Id = 1 };
var user2 = user1; //same reference
我可以编写一些帮助代码来规范化引用,但我更确切地说EF只是知道它们是基于ID的同一个对象。
至于为什么EF这样做,一种解释可能是它试图避免对同一对象进行多重CRUD操作,因为同一实体的单独实例可能包含不同的数据。我希望能够告诉EF不要担心这一点。
更新
所以我怀疑上面的上一段。由于没有办法告诉EF不要在任何一个实例上做CRUD,我现在就这样做:
if (address.ModifiedBy.Id == address.CreatedBy.Id)
{
address.ModifiedBy = address.CreatedBy;
}
只要我不想在任何一个上做CRUD,就可以运行得很好。
UPDATE2
我以前曾这样做是为了防止EF在需要的时候验证其他所需的null属性是子实体的ID。但是,它不会使EF在具有相同ID的单独实例上进入tizzy。如果它不会对任何AppUser
对象执行CRUD,为什么它关心实例是否不同?
foreach (var o in new object[] { address.ModifiedBy, address.CreatedBy })
{
db.Entry(o).State = EntityState.Unchanged;
}
答案 0 :(得分:0)
您可以添加两个额外属性以使主对象的Id为bash$> cat upper_lower.sh
#!/bin/bash
# Main loop to process the words passed to script in ARGV array
for w in $@
do
echo $w | while read word
do
# Matching lowercase only
if [[ $word =~ ^[a-z] ]]
then
echo $word >> aa
fi
# Matching UPPERCASE only
if [[ $word =~ ^[A-Z] ]]
then
echo $word >> bb
fi
# Matching digits only
if [[ $word =~ ^[0-9] ]]
then
echo $word >> cc
fi
done
done
l=`cat aa|wc -l` # Taking lowercase count
u=`cat bb|wc -l` # Taking uppercase count
d=`cat cc|wc -l` # Taking digits count
echo; echo "$l words are lowercase" # Added extra echo just to print new line.
echo; echo "$u words are uppercase"
echo; echo "$d words are digits"
rm aa bb cc # removing temp files after processing
bash$>
,然后您只能使用一个AppUser
对象,并为已创建和已修改的属性引用它。
AppUser
否则,您的代码最终会通过使用相同的主键保存两个CreatedById = user1.Id,
ModifiedById = user1.Id
实例。
另一种方法是将外键属性设置为仅一个AppUser
对象
答案 1 :(得分:0)
如果从上下文中获得AppUser
,那么您将不需要执行任何操作,因为实体框架将跟踪实体:
var user1 = context.AppUsers.Find(1);
var user2 = context.AppUsers.Find(1);
var address = new Address
{
CreatedBy = user1, //different reference
ModifiedBy = user2 //different reference
};
现在,他们都会指向相同的对象,不会导致冲突。
答案 2 :(得分:0)
解释是EF的更改跟踪器是identity map。即数据库中的记录映射到一个CLR对象,而且只有一个。
这可以通过尝试使用相同的键附加两个对象来轻松演示:
CreatedBy = user1, //different reference
ModifiedBy = user2 //different reference
第二行会抛出异常:
附加' AppUser'失败,因为同一类型的另一个实体已具有相同的主键值。
如果您指定
,也会发生这种情况user1
在此过程的某个地方,user2
和Id
必须附加到上下文中,从而产生您获得的异常。
显然,您有一个函数可以接收两个可能不同或相同的AppUser
值。不可否认,如果您只需从这些Id
创建两个if (address.ModifiedBy.Id == address.CreatedBy.Id)
实例,就可以非常方便,而不必担心相同的密钥。不幸的是,你的解决方案......
<section id="be" class="pad-xl">
<div class="container"><!--tab contaire-->
<ul id="tabs" class="nav nav-tabs nav-justified" role="tablist">
<li class="active"><a href="#plani" data-toggle="tab">La Planification</a></li>
<li ><a href="#quali" data-toggle="tab">La qualité</a></li>
<li ><a href="#prod" data-toggle="tab">La production</a></li>
<li ><a href="#config" data-toggle="tab">Le configurateur</a></li>
</ul>
<div class="tab-content"><!--tab content-->
<div role="tabpanel" class="tab-pane fade in active" id="plani"><!--tab panel-->
<div class="row"><!--2 Blocs-->
<div class="col-xs-4 feature wow fadeInLeft" data-wow-delay="0.3s"><!--FEATURES -->
<div class="list-group">
<a href="#" data-seek="53.6" class="timecode list-group-item active">Introduction<span class="badge">14</span></a>
<a href="#" data-seek="53.6" class="timecode list-group-item list-group-item-action">Blabla</a>
<a href="#" data-seek="53.6" class="timecode list-group-item list-group-item-action">Blabla2</a>
<a href="#" data-seek="53.6" class="timecode list-group-item list-group-item-action">Blabla3</a>
<a href="#" data-seek="53.6" class="timecode list-group-item list-group-item-action">Blabla4</a>
<a href="#" data-seek="53.6" class="timecode list-group-item list-group-item-action">5</a>
</div>
</div>
<div class="col-xs-8 feature wow fadeInLeft" data-wow-delay="0.3s"><!--FEATURES -->
<div class="embed-responsive embed-responsive-16by9">
<iframe id="thevideo" class="embed-responsive-item" src="//player.vimeo.com/video/181964440?api=1" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
</div
</div></div>
</div><!--2 Blocs-->
</div><!--tab panel-->
<div role="tabpanel" class="tab-pane fade" id="quali"><!--tab panel-->
<div class="row"><!--2 Blocs-->
<div class="col-xs-4 feature wow fadeInLeft" data-wow-delay="0.3s"><!--FEATURES -->
<div class="list-group">
<a href="#" data-seek="53.6" class="timecode list-group-item active">Introduction<span class="badge">14</span></a>
<a href="#" data-seek="53.6" class="timecode list-group-item list-group-item-action">PIC & Plan d’approvisionnement</a>
<a href="#" data-seek="53.6" class="timecode list-group-item list-group-item-action">PDP</a>
<a href="#" data-seek="53.6" class="timecode list-group-item list-group-item-action">Plan de charges</a>
<a href="#" data-seek="53.6" class="timecode list-group-item list-group-item-action">L’ordonnancement</a>
<a href="#" data-seek="53.6" class="timecode list-group-item list-group-item-action">Autres fonctionnalités Planification</a>
</div>
</div>
<div class="col-xs-8 feature wow fadeInLeft" data-wow-delay="0.3s"><!--FEATURES -->
<div class="embed-responsive embed-responsive-16by9">
<iframe id="thevideo" class="embed-responsive-item" src="//player.vimeo.com/video/181964440?api=1" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
</div>
</div>
</div><!--2 Blocs-->
</div><!--tab panel-->
</div>
<script>
jQuery(function ($) {
var iframe = document.getElementById('thevideo');
var player = $f(iframe);
$('.timecode').on('click', function (e) {
e.preventDefault();
var seekVal = $(this).attr('data-seek');
player.api('seekTo', seekVal);
});
});
//@ sourceURL=pen.js
</script>
</section>
......是必要的。但是很坚固。