【问题标题】:Linq query deleting multiple rows instead of one. Very Simple QueryLinq 查询删除多行而不是一行。非常简单的查询
【发布时间】:2019-11-20 19:23:34
【问题描述】:

这应该很简单,但我认为我的模型可能存在问题。我已经使用 linq 一年多了,我应该可以轻松完成这个简单的删除。请帮忙! 当我只想删除一条记录时,它会从数据库中删除两条记录

我有一个包含这些属性的数据库表。

Email, EmployeeName, StoreId
jsch@m.com,Joe Schneider,9
jsch@m.com,Joe Schneider,8

我需要删除 storeId 为 9 的 Joe Schneider

所以我运行这个简单的查询和删除过程。

        var temp2 = difference[i];
        var PersonToRemove = db.Permissions.SingleOrDefault(s => s.EmployeeName == temp2 && s.StoreId == Persons.StoreId);
        if (PersonToRemove.EmployeeName != null)
        {
            db.Permissions.Remove(PersonToRemove);
            db.SaveChanges();
        }

我假设有人会说,嘿,您的模型不正确,不要将名称作为键,但我不能只是更改模型,因为应用程序的其他部分基于此模型并会造成巨大的休息。您能给我建议如何编辑 linq 查询以不删除两条记录吗?

型号

  [Table("Permissions")]
    public class Permissions
    {
        [Key]
        public String EmployeeName { get; set; }

        public string Department { get; set; }
        public int? StoreId { get; set; }

        public String Email { get; set; }
    }

【问题讨论】:

  • 两条记录具有相同的键(EmployeeName)。删除可能仅通过查看密钥来删除。
  • 您是如何设法插入标记为键的重复值
  • @Eldar我不知道为什么它允许我插入标记为键的重复值,但它在 ssms 中以这种方式显示。 @Suphant Persons.StoreId 在我的方法中作为参数传递,在这种情况下该值为 9,因为我想删除 StoreId 为 9 的 Joe
  • 我认为你有一个更大的重复键问题,这导致了这个问题
  • 员工姓名对于 Key 来说似乎是个坏主意...人们可以有相同的姓名。你为什么不只有一个 Id identity int 列?

标签: c# .net asp.net-mvc linq


【解决方案1】:
[Table("Permissions")]
public class Permissions
{
    [Key]

    public String EmployeeName { get; set; }
}

问题在于您在这里定义了一个没有长度限制的主键。 (MaxLength)。这导致 EF 生成带有 NVARCHAR(MAX) 的列。如前所述 here VARCHAR(MAX) 列不允许作为主键。所以正确的定义应该如下所示

[Table("Permissions")]
public class Permissions
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)] <--
    [MaxLength(255)] // <---
    public String EmployeeName { get; set; }
}

编辑:您需要重新创建数据库才能使用正确的设置初始化关联的表。 编辑 2:您可能还需要一个 DatabaseGenerated(DatabaseGeneratedOption.None) 因为它不是标识列。

【讨论】:

  • 我添加了一张桌子细节的图片。我还添加了 MaxLength(255) 部分,但它仍然删除了两个
  • 您需要重新创建数据库。
  • 好吧,我无法重新创建数据库,因为创建和修改表需要两年半的时间,但我确实重新创建了表。感谢您的输入,你们所有人共同带领我添加了一个自动递增的 ID 列。我害怕这样做,因为它已经上线了,但现在我这样做了,我不得不改变我的模型,一切都按预期工作。谢谢!
【解决方案2】:

您可以像这样在单个实体上设置Deleted 状态:

var temp2 = difference[i];
var PersonToRemove = db.Permissions.SingleOrDefault(s => s.EmployeeName == temp2 && s.StoreId == Persons.StoreId);
if (PersonToRemove.EmployeeName != null)
{
    db.Entry(PersonToRemove).State = EntityState.Deleted; // do this instead
    db.SaveChanges();
}

然后 EF 应该找出您要删除的实体

UPD 我假设您使用的是 EF6 和 DB-first 方法。我还假设您已经使用默认约定模型构建器设置了数据库上下文类。似乎 EF 基于 Key 的默认对象跟踪将不起作用,因为您的密钥不是唯一的(这是一个更大的问题,但我知道您已经意识到这一点)。

您可以尝试通过添加自定义模型构建器配置来规避该约定,如下所示:

class MyDbContext : DbContext { 
    public virtual DbSet<Permissions> Permissions {get;set;}

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Permissions>().HasKey(p => new { p.EmployeeName, p.StoreId});
    }
}

由于您没有分享您的 DbContext 定义,这只是一个 sn-p,但希望能给您一些探索的想法。 这是 API 参考:https://docs.microsoft.com/en-us/dotnet/api/system.data.entity.modelconfiguration.entitytypeconfiguration-1?view=entity-framework-6.2.0

【讨论】:

  • 仍然没有 timur
  • 我看到您发布的列属性概述了 EmployeeName 是一个键 - 我们可以看到相应的表定义吗?我有点好奇,您如何在示例数据中拥有两个具有非唯一 EmployeeName 的不同记录 - 某处是否有复合键?
  • Entity 无法决定要从数据库中删除什么。它决定了它将用已删除标志标记的条目,就像您在上面所做的那样。只需要生成一条 SQL 语句。由于主键设置错误,该 SQL 语句将删除这两个值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-12-06
  • 2016-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多