项目创建儿童问题
我对代码第一个应用程序有问题。 当我尝试在数据库中插入测试项目时,我在儿童问题上已经存在错误。
在这里,我的newitem操作的代码:
public async Task<ActionResult<Event>> NewEvent(Event newEvent)
{
if (await _context.Events.CountAsync() > 0 && await _context.Events.FindAsync(newEvent.Id) is not null)
return BadRequest(new ConstraintException("Event Already Exist"));
if (newEvent.DoorPrize is not null && newEvent.DoorPrize.Count() > 0)
{
var doorPrizes = newEvent.DoorPrize.Where(d => _context.DoorPrizes.Contains(d)).ToList();
foreach (DoorPrize doorPrize in doorPrizes)
{
_context.Entry(doorPrize).State = EntityState.Detached;
}
foreach (DoorPrize doorPrize in newEvent.DoorPrize)
{
if (_context.FairlightUsers.Contains(doorPrize.Sponsor))
_context.Entry(doorPrize.Sponsor).State = EntityState.Detached;
}
}
if (newEvent.AttendeeDetails is not null && newEvent.AttendeeDetails.Count() > 0)
{
var attendeeDetails = _context.EventAttendeeDetails.Where(d => newEvent.AttendeeDetails.Contains(d)).ToList();
foreach (EventAttendeeDetail attendeeDetail in attendeeDetails)
{
_context.Entry(attendeeDetail).State = EntityState.Detached;
}
}
if (newEvent.VenueAddress is not null)
{
if (_context.Addresses.Contains(newEvent.VenueAddress))
_context.Entry(newEvent.VenueAddress).State = EntityState.Detached;
}
if (newEvent.Sponsor is not null)
{
if (_context.FairlightUsers.Contains(newEvent.Sponsor))
_context.Entry(newEvent.Sponsor).State = EntityState.Detached;
}```
I don't know why, even if I make Sponsors (the 2) to detached, the application still try to add one.
Is someone see where is my mistake ?
My goal would be to avoid any child insertion because app need to take it from existing list but I don't success to achieve this. the application always try to create children event with setting them as detached. is there a method to avoid this ?
I have an issue with a code first app.
When I tried to insert test item in my database I have an already exist error on child issue.
here the code of my newitem Operation :
public async Task<ActionResult<Event>> NewEvent(Event newEvent)
{
if (await _context.Events.CountAsync() > 0 && await _context.Events.FindAsync(newEvent.Id) is not null)
return BadRequest(new ConstraintException("Event Already Exist"));
if (newEvent.DoorPrize is not null && newEvent.DoorPrize.Count() > 0)
{
var doorPrizes = newEvent.DoorPrize.Where(d => _context.DoorPrizes.Contains(d)).ToList();
foreach (DoorPrize doorPrize in doorPrizes)
{
_context.Entry(doorPrize).State = EntityState.Detached;
}
foreach (DoorPrize doorPrize in newEvent.DoorPrize)
{
if (_context.FairlightUsers.Contains(doorPrize.Sponsor))
_context.Entry(doorPrize.Sponsor).State = EntityState.Detached;
}
}
if (newEvent.AttendeeDetails is not null && newEvent.AttendeeDetails.Count() > 0)
{
var attendeeDetails = _context.EventAttendeeDetails.Where(d => newEvent.AttendeeDetails.Contains(d)).ToList();
foreach (EventAttendeeDetail attendeeDetail in attendeeDetails)
{
_context.Entry(attendeeDetail).State = EntityState.Detached;
}
}
if (newEvent.VenueAddress is not null)
{
if (_context.Addresses.Contains(newEvent.VenueAddress))
_context.Entry(newEvent.VenueAddress).State = EntityState.Detached;
}
if (newEvent.Sponsor is not null)
{
if (_context.FairlightUsers.Contains(newEvent.Sponsor))
_context.Entry(newEvent.Sponsor).State = EntityState.Detached;
}```
I don't know why, even if I make Sponsors (the 2) to detached, the application still try to add one.
Is someone see where is my mistake ?
My goal would be to avoid any child insertion because app need to take it from existing list but I don't success to achieve this. the application always try to create children event with setting them as detached. is there a method to avoid this ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
与独立实体合作是令人讨厌的。使用独立实体图是一个完全的痛苦。您的方法有几个问题,即在与独立实体合作时,数据库状态应始终将视为您仅在验证它们是在验证之后才能应用独立状态的更改的真实点仍然有意义。 (即,自您当前副本已被删除以来,其他人都没有修改实体数据。
首先,
完全不必要。为什么要告诉DBContext执行计数并加载实体以确定实体是否存在?如果您是否存在?想要知道一个实体是否存在:
数据库,则执行
如果存在的 对于运行需要一些时间的操作
。通常,要不是想要脱离现有实体,尤其是参考文献,要被脱离的实体覆盖。简而言之,无论是虫子还是恶意消费者。例如,如果服务器发送要渲染的独立实体的Web应用程序,则客户端呈现要更改的字段,然后将form或ajax post(JavaScript)序列化数据将数据序列化到实体类中以发送到服务器,很容易错过导致#nulls的值,恶意用户可以使用浏览器调试工具来拦截帖子,查看实体数据并进行更改,例如上面的代码可以不知不觉地覆盖数据。通过的东西可能看起来像一个实体,但通常不是。
取而代之的是,没有改变独立的实体图被传递给它的事实,而是将其像对待DTO一样。事件中的数据将作为一个新实体,但是与之相关的所有实体都需要确定这些实体是代表新实体还是对现有的实体的参考。因此,例如,如果事件和门plize之间的关系是一对一的,那么在新事件中将创建一个门布实体,并且只有与该实体相关联,则应允许将其与该实体插入实体。相反,如果Dotrize是其自己的实体,并且仅与此事件(和其他事件)相关联,那么它需要与数据状态重新搭配。
两者之间的差异:1-1对数(事件拥有DOORPRIZES)数据库中的差异将在Doorprize表上具有EvenID。多一到许多(事件与Doorpriess相关联)将有一个EventDoorprize链接表,其中包含EventId&amp; doorprizeid。
在第一种情况下,如果将事件视为新事件,则门奖都应该是新的。但是,Doorprize与赞助商之间的关系很可能是一个多对多的协会,其中一个赞助商很可能会在不同的事件中与许多不同的门奖相关联。
拥有所有权,如果客户消费者正在为实体生成新ID(不建议使用,最好利用身份列之类的东西并让数据库来管理),那么您可能需要检查新的Doorprize记录是否 在DB中。这里的目的不是要替换现有的门奖品,而是要提出数据
例外由消费者设置,例如使用有意义的密钥或GUID.NEW()
处理关联需要更多的关注。如果预期有门牌并与新事件相关联,那么我们需要找到这些事件。如果此请求需要处理该请求的一部分可能会创建新的DoorPrize实体,那么也需要处理。一般而言,最好从原子上处理事物,在该事件中创建与门奖相关联的事件将为此造成责任。如果有一项新的门奖的操作,那么将通过一个单独的电话来处理。
例如,如果门牌与事件“关联”(多对多关系),
那么这给我们带来了匹配的真实门奖实体的列表。我们将希望将这些与新事件相关联。添加活动时,可能会添加任何新的门奖。这里的最后一步将适用于两个方案,将赞助商与任何新的Doorprize相关联。在一对一的场景中,这将是每一个门奖,在多对多的人中,这只是可能添加的不存在的奖品:
1到Many示例:
多对多的示例:
1到MONEY示例:
类似的操作来处理赞助商的协会,差异是,如果门牌是关联,我们只想在新添加的门奖品上代替赞助商。我们从上下文追踪实体重新相关的门奖品已经有有效的赞助商。
稍后,当您执行更新时,这是一个类似的过程,除了您期望获取现有实体,还可以通过急切的加载预先提取相关的详细信息:
如果找不到条目,这将投掷,这将是您可以捕获的,或调用
.SingleordEfault
,然后检查#Null以返回您的BadRequest,如果您喜欢内联行动。从那里,您可以通过在哪里检查与现有访问者的详细信息,以确定是否需要更新,添加或删除DoorPriess。同样,为了添加门提示相同的过程,以将赞助商与实际跟踪实例重新合并。更新实体图(亲子关系或关联)时,重要的是要区分较高级别的实体是否“拥有”该关系,或者它是数据库中可能已经存在的实体之间的关联。您将需要 避免 代码,该代码将跟踪的实体分离,然后执行诸如将传递的实体状态设置以修改要保存的事情。这将导致各种问题的界限,您覆盖您不打算更改的数据,或者当EF/SQL被告知做一些无效的事情时。
Working with detached entities are a nuisance. Working with detached entity graphs are a complete pain. There are several issues with your approach, namely when working with detached entities, the database state should always be treated as the point of truth for which you apply changes from your detached state only after you validate that they are still relevant. (I.e. someone else hasn't modified the entity data since your current copy had been taken.
First off,
is completely unnecessary. Why would you tell the DbContext to execute a count AND load the entity just to determine if the entity exists? If you want to know if an entity exists:
This executes an
IF EXISTS SELECT
against the database which is much faster.Not every operation on the DbContext needs to be
async
. Asynchronous calls are useful for operations that will take some time to run. They come with an small extra performance cost so any operation that can be done quickly such as fetching individual entities or reasonable entity graphs can just be done synchronously.Next, when dealing with detached entities you generally do not want to detach existing entities, and especially not references, to be overwritten by the detached entities coming in. In short you should never trust data coming into the domain to be current or safe from unexpected tampering, either by bugs or malicious consumers. For example if you have a web application where the server sends an detached entity to be rendered, then the client presents fields to be changed then the Form or Ajax POST (Javascript) serializes data into an Entity class to send back to the server, it is very easy to miss values resulting in #nulls, and malicious users can use browser debugging tools to intercept the POST, view the entity data and make changes which code like the above could unwittingly overwrite data. What gets passed in may look like an entity, but it is often not.
Instead, without changing the fact that a detached entity graph is being passed in, treat it like a DTO. The data in Event will serve as a new entity, but everything related to it you will need to decide whether those represent new entities or references to existing ones. So for instance if the relationship between an Event and a DoorPrize is one to many, where a DoorPrize entity would be created with the new event, and only ever associated with that entity, then it stands that it should be allowed to be inserted with that entity. If instead the DoorPrize is its own entity and merely associated with this Event (and others) then it needs to be re-associated with the data state.
The difference between the two: 1-to-many (Event owns DoorPrizes) in the database would have an EventId on the DoorPrize table. Many-to-many (Event is associated with DoorPrizes) There would be an EventDoorPrize linking table containing the EventId & DoorPrizeId.
In the first case, if the event is considered as New, the door prizes should all be new. However, the relationship between DoorPrize and Sponsor is most likely a many-to-many association where one sponsor will likely be associated with many different door prizes across different events.
With ownership, if a client consumer is generating new IDs for entities (not recommended, it's better to leverage things like Identity columns and let the database manage that) then you might need to check that new DoorPrize records are not in the DB. The point here wouldn't be to replace existing Door Prizes if found, but to throw a data exception since we expect to be adding these new children:
Example if DoorPrizes are "owned" by Events (1-to-many relationship) but DoorPrizeIds are set by the consumer such as using a meaningful key or Guid.New()
Dealing with associations requires a bit more attention. If DoorPrizes are expected to exist and are associated with a new Event then we need to locate those. If this request needs to handle that new DoorPrize entities might be created as part of this request, then that would need to be handled as well. As a general rule it is better to handle things more atomically where creating an Event that associates with door prizes would be responsible for just that. If there was an operation to create a new Door Prize then that would be handled by a separate call.
Example if DoorPrizes are "associated" to Events (many-to-many relationship)
What this gives us is a list of matching real Door Prize entities to associate. We will want to associate these in place of the data that came in with the new event. Any door prizes that might be new would be added when the event is added. The final step here will apply to both scenarios which will be to associate the sponsors to any new DoorPrize. In the one-to-many scenario that would be every door prize, in the many-to-many that would just be the non-existing ones that might be added:
1-to-many example:
Many-to-many example:
1-to-many example:
A similar operation to deal with associations for the Sponsor, the difference just being if the DoorPrizes are associations, we only want to do the substitution for Sponsors on newly added door prizes. The door prizes we re-associated from context tracked entities will already have valid sponsors.
Later, when you perform updates, it is a similar process, except you would expect to fetch the existing entity, but also pre-fetch the associated details with eager loading:
This will throw if the entry isn't found which you can catch, or call
.SingleOrDefault
and check for #null to return your BadRequest if you prefer doing it inline. From there it is much the same process by where you can inspect the details coming un with the existingEntry to determine if DoorPrizes need to be updated, added, or removed. Again, for adding DoorPrizes the same process to re-associate Sponsors with actual tracked instances.The important thing when updating entity graphs (parent-child relationships or associations) is to differentiate between whether the higher level entity "owns" the relationship, or if it is an association between entities that may already exist in the database. You will want to avoid code that detaches tracked entities and then does things like setting a passed in entity state to Modified to be saved. This will lead to all manners of problems where you overwrite data you don't intend to change, or exceptions when EF/SQL get told to do something invalid.