C# 使用实体框架将不同的记录插入带有外键的表中
这些是我的模型,我使用实体框架,采用代码优先的方法C# 使用实体框架将不同的记录插入带有外键的表中,c#,asp.net,entity-framework,asp.net-web-api,C#,Asp.net,Entity Framework,Asp.net Web Api,这些是我的模型,我使用实体框架,采用代码优先的方法 public class Respondent { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int RespondentId { get; set; } public User Requester { get; set; } public User Provider { get; set; }
public class Respondent
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int RespondentId { get; set; }
public User Requester { get; set; }
public User Provider { get; set; }
public string Role { get; set; }
}
public class User: IUser
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public int UPI { get; set; }
public string Name { get; set; }
}
这是两个生成表之间的关系
我想要的是,若用户表中存在用户,那个么不要创建另一个用户条目
问题是当我添加一个新的提供者(类型为user)时,每次它在user中创建一个新条目时,即使该用户存在;我想要的是在表中添加该用户的引用
private Context db = new Context();
public async Task<IHttpActionResult> PostRespondent(Respondent respondent)
{
var TempProvidersList = respondent.Providers.ToList();
try
{
var requester = db.Users.Single(s => s.UserId == respondent.Requester.UserId);
requester.IsPublic = false;
var providerIds = respondent.Providers.Select(x => x.UPI).ToList();
foreach (var providerId in providerIds)
{
if (!db.Respondents.Any(x => x.Requester.UserId == requester.UserId && x.Provider.UPI == providerId))
{
var provider = respondent.Providers.Single(x => x.UPI == providerId);
provider.IsPublic = true;
db.Respondents.Add(new Respondent() { Requester = requester, Provider = provider, Role = provider.Role });
}
}
db.SaveChanges();
}
catch (Exception ex)
{
}
return CreatedAtRoute("DefaultApi", new { id = respondent.RespondentId }, respondent);
}
private Context db=new Context();
公共异步任务后响应者(响应者-响应者)
{
var TempProvidersList=响应者.Providers.ToList();
尝试
{
var requester=db.Users.Single(s=>s.UserId==responder.requester.UserId);
requester.IsPublic=false;
var providerIds=appender.Providers.Select(x=>x.UPI.ToList();
foreach(providerId中的变量providerId)
{
if(!db.responders.Any(x=>x.Requester.UserId==Requester.UserId&&x.Provider.UPI==providerId))
{
var provider=响应者.Providers.Single(x=>x.UPI==providerId);
provider.IsPublic=true;
添加(新的响应者(){Requester=Requester,Provider=Provider,Role=Provider.Role});
}
}
db.SaveChanges();
}
捕获(例外情况除外)
{
}
返回CreatedAtRoute(“DefaultApi”,新的{id=respondent.RespondentId},respondent);
}
我认为问题在于传递由不同DbContext加载的实体,然后在新的DbContext中添加对这些实体的引用
这里的代码没有多大意义:
var res = db.Respondents
.Include(user => user.Requester)
.Include(user => user.Provider)
.Where(o => o.Requester.UserId == requester.UserId ).ToList();
代码中任何地方都不使用“res”。你用的是“a”吗?我想是同一个词?
首先,如果您只想检查是否存在行,请使用Any()
而不是加载所有可用的实体,只是为了检查是否存在某些实体
我看到的问题是:
tempProvider = TempProvidersList[i];
db.Respondents.Add(new Respondent() { Requester = requester, Provider = tempProvider, Role = TempProvidersList[i].Role });
这是将新响应中的提供者引用设置为可能从其他DbContext实例加载的用户(提供者)
要解决此问题,应从当前DbContext加载您设置的任何引用:
var providerIds = respondent.Providers.Select(x => x.UPI).ToList();
var providers = db.Users.Where(x => providerIds.Contains(x.UPI)).ToList();
var requester = db.Users.Single(s => s.UserId == respondent.Requester.UserId);
requester.IsPublic = false;
foreach(var providerId in providerIds)
{
if (!db.Respondents.Any(x => x.Requester.UserId == requester.UserId))
{
var provider = providers.Single(x => x.UPI == providerId);
provider.IsPublic = true;
db.Respondents.Add(new Respondent() { Requester = requester, Provider = provider, Role = provider.Role });
}
}
db.SaveChanges();
我选择根据ID一次加载所有适用的提供者,而不是在循环中一次加载一个提供者。在循环中,我只是尝试从加载的集合中检索与ID匹配的那个
我会用try/catch块包装它并处理异常。可能出现的例外情况是,找不到ProviderId的用户。(可以删除用户吗?)我对ID而不是加载的引用进行了foreach,因为基于上述条件,该集合可能没有针对每个ID的实体。(如果6个ID中只有5个加载提供者用户,则ID集合将有6个元素,但实体集合将只有5个)
这里的另一点是使用
Single
而不是FirstOrDefault
,在这里您需要一条记录。这将强制执行该规则,如果存在多个或没有匹配的记录,则将引发异常。只有在预期结果是找不到行时,才应使用“OrDefault”变量FirstOrDefault
将在多个匹配项进入数据库时隐藏问题,如果没有“OrderBy”子句,则无法依赖将返回哪个引用。我认为问题是由于传递由不同DbContext加载的实体,然后在新的DbContext中添加对这些实体的引用
这里的代码没有多大意义:
var res = db.Respondents
.Include(user => user.Requester)
.Include(user => user.Provider)
.Where(o => o.Requester.UserId == requester.UserId ).ToList();
代码中任何地方都不使用“res”。你用的是“a”吗?我想是同一个词?
首先,如果您只想检查是否存在行,请使用Any()
而不是加载所有可用的实体,只是为了检查是否存在某些实体
我看到的问题是:
tempProvider = TempProvidersList[i];
db.Respondents.Add(new Respondent() { Requester = requester, Provider = tempProvider, Role = TempProvidersList[i].Role });
这是将新响应中的提供者引用设置为可能从其他DbContext实例加载的用户(提供者)
要解决此问题,应从当前DbContext加载您设置的任何引用:
var providerIds = respondent.Providers.Select(x => x.UPI).ToList();
var providers = db.Users.Where(x => providerIds.Contains(x.UPI)).ToList();
var requester = db.Users.Single(s => s.UserId == respondent.Requester.UserId);
requester.IsPublic = false;
foreach(var providerId in providerIds)
{
if (!db.Respondents.Any(x => x.Requester.UserId == requester.UserId))
{
var provider = providers.Single(x => x.UPI == providerId);
provider.IsPublic = true;
db.Respondents.Add(new Respondent() { Requester = requester, Provider = provider, Role = provider.Role });
}
}
db.SaveChanges();
我选择根据ID一次加载所有适用的提供者,而不是在循环中一次加载一个提供者。在循环中,我只是尝试从加载的集合中检索与ID匹配的那个
我会用try/catch块包装它并处理异常。可能出现的例外情况是,找不到ProviderId的用户。(可以删除用户吗?)我对ID而不是加载的引用进行了foreach,因为基于上述条件,该集合可能没有针对每个ID的实体。(如果6个ID中只有5个加载提供者用户,则ID集合将有6个元素,但实体集合将只有5个)
这里的另一点是使用
Single
而不是FirstOrDefault
,在这里您需要一条记录。这将强制执行该规则,如果存在多个或没有匹配的记录,则将引发异常。只有在预期结果是找不到行时,才应使用“OrDefault”变量FirstOrDefault
将隐藏多个匹配项进入DB的问题,如果没有“OrderBy”子句,您无法依赖将返回的引用。“响应者”来自客户。就EF而言,它是一个POCO类,而不是一个跟踪实体。引用“TempProvidersList”中的任何实体或其相关类将被视为全新实体,从而插入重复项。这就是为什么在客户机和服务器之间传递实体是个坏主意的例子。在你的方法中尝试上面的代码,看看是否仍然有重复的代码。你能将当前代码作为编辑附加到原始问题中吗?var provider=append.Providers.Sin