【问题标题】:C# ASP.Net - Error when trying to delete data from tableC# ASP.Net - 尝试从表中删除数据时出错
【发布时间】:2017-08-29 11:19:02
【问题描述】:

我有表格 Player 和表格 Statistic 以及在这个问题中不重要的其他表格。 Table Player 有 PK Player_ID,它在 table Statistic 中是 FK。这些表之间的关系是一对多的(一个玩家可以拥有更多的统计数据)。

代码如下: GenericRepository(我已经创建了它以具有独特的 CRUD 方法类)

public async Task<int> Delete<T>(Guid id) where T : class
{
        try
        {
            T entity = await Get<T>(id);
            Context.Set<T>().Remove(entity);
            return await Context.SaveChangesAsync();
        }
        catch (Exception ex)
        {
            throw ex;
        }
}

PlayerRepository(用于管理对 Player 表的操作)

public async Task<int> Delete(Guid id)
{
        try
        {
            var player = await GenRepository.Get<Player>(id);
            if (player == null)
            {
                return 404;
            }
            else
            {
                return await GenRepository.Delete(player);
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
}

PlayerService(WebAPI中repository和controller的连接)

public async Task<int> Delete(Guid id)
{
        try
        {
            return await PlayerRepository.Delete(id);
        }
        catch (Exception ex)
        {
            throw ex;
        }
}

播放器控制器

[HttpDelete]
    [Route("deleteplayer")]
    public async Task<HttpResponseMessage> Delete(Guid id)
    {
        try
        {
            var Finder = Mapper.Map<PlayerView>(await PlayerService.Get(id));
            if(Finder == null)
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Player doesn't exist in database.");
            }

            var Response = await PlayerService.Delete(id);
            var profile = "../../../app/pictures/FootballFanAppPictures/" + Finder.Club_ID.ToString().ToUpper() + "/profiles/" + id.ToString().ToUpper() + ".png";
            var details = "../../../app/pictures/FootballFanAppPictures/" + Finder.Club_ID.ToString().ToUpper() + "/" + id.ToString().ToUpper() + ".png";
            if (System.IO.File.Exists(profile))
            {
                System.IO.File.Delete(profile);
            }
            if (System.IO.File.Exists(details))
            {
                System.IO.File.Delete(details);
            }
            return Request.CreateResponse(HttpStatusCode.OK, Response);
        }
        catch(Exception ex)
        {
            return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex);
        }
    }

实体模型:

-数据库模型

 public partial class Player
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Player()
    {
        this.Statistic = new HashSet<Statistic>();
    }

    public System.Guid Player_ID { get; set; }
    public System.Guid Club_ID { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
    public double Height { get; set; }
    public int Weight { get; set; }
    public System.DateTime BirthDate { get; set; }
    public string Nationality { get; set; }
    public string Position { get; set; }
    public int Shirtnmbr { get; set; }

    public virtual Club Club { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Statistic> Statistic { get; set; }
}
using System;
using System.Collections.Generic;

public partial class Statistic
{
    public System.Guid Statistic_ID { get; set; }
    public System.Guid Player_ID { get; set; }
    public int Goals { get; set; }
    public int Assists { get; set; }
    public int FoulsFor { get; set; }
    public int FoulsAgainst { get; set; }
    public int ShotsTotal { get; set; }
    public int ShotsGoal { get; set; }

    public virtual Player Player { get; set; }
}

-域模型(在存储库中使用)

public class PlayerDomain : IPlayerDomain
{
    public Guid Player_ID { get; set; }
    public Guid Club_ID { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
    public double Height { get; set; }
    public int Weight { get; set; }
    public DateTime BirthDate { get; set; }
    public string Nationality { get; set; }
    public string Position { get; set; }
    public int Shirtnmbr { get; set; }
    public virtual ICollection<IStatisticDomain> Statistic { get; set; }
}
public class StatisticDomain: IStatisticDomain
{
    public Guid Statistic_ID { get; set; }
    public Guid Player_ID { get; set; }
    public int Goals { get; set; }
    public int Assists { get; set; }
    public int FoulsFor { get; set; }
    public int FoulsAgainst { get; set; }
    public int ShotsTotal { get; set; }
    public int ShotsGoal { get; set; }
}

-查看模型(用于控制器)

public class PlayerView
{
    public Guid Player_ID { get; set; }
    public Guid Club_ID { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
    public double Height { get; set; }
    public int Weight { get; set; }
    public DateTime BirthDate { get; set; }
    public string Nationality { get; set; }
    public string Position { get; set; }
    public int Shirtnmbr { get; set; }
    public virtual ICollection<StatisticView> Statistic { get; set; }
}
public class StatisticView
{
    public Guid Statistic_ID { get; set; }
    public Guid Player_ID { get; set; }
    public int Goals { get; set; }
    public int Assists { get; set; }
    public int FoulsFor { get; set; }
    public int FoulsAgainst { get; set; }
    public int ShotsTotal { get; set; }
    public int ShotsGoal { get; set; }
}

每个类都在一个单独的文件中。我使用数据库优先方法,所以我得到了 .edmx 文件和数据库模型。数据库是在 SQL Server Management Studio 中创建的。

我可以更新播放器,但是当我尝试删除它时,我收到了这个错误:

操作失败:无法更改关系,因为一个或多个外键属性不可为空。当对关系进行更改时,相关的外键属性将设置为空值。如果外键不支持空值,则必须定义新关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。

我在 google 和 stackoverflow 上搜索了各种答案,但找不到解决我问题的答案

【问题讨论】:

标签: c# asp.net sql-server entity-framework


【解决方案1】:

在调用此行之前:

var Response = await PlayerService.Delete(id);

您将需要检索分配给您尝试删除的玩家的统计数据列表。

然后循环遍历每个统计信息并首先从数据库中删除这些统计信息。

var stats = Finder.Statistic.ToList();

if(stats != null && stats.Any())
{
   foreach(var stat in stats)
   { 
      //retrieve your stat record here from the database
      //check that the stat record is not null
      //delete your stat record here
   }
}

那么您应该能够删除您的玩家记录,因为不再有对其的引用。

您可以将 ON DELETE CASCADE 设置为 true,但您需要注意完全了解播放器删除时将删除的所有内容。

【讨论】:

  • 天啊。很简单。我现在就试试。这是有道理的,我无法理解。谢谢你:)
  • 如果我这样做:var x = await StatisticService.Delete(stat.Statistic_ID); 我收到错误“对象引用未设置为对象的实例”。
  • 当我无法调试代码时,很难知道这是指什么。您确定 StatisticService 已初始化吗?在将其传递给 Delete 之前,您是否检查了 stat 不为空?
  • 当您将玩家记录映射到您的玩家观看记录时,是否也会映射统计数据?
  • 在两个组件的帮助下,我在两个 .html 文件中使用了两个模态(我使用 Angular)。首先删除统计,其次删除播放器。您的回答被认为是正确的:)
【解决方案2】:

我没有在您的代码中看到有关 Player delete 的统计信息删除。 在删除玩家之前,您需要先删除所有与玩家相关的统计信息。如果有剩余,播放器将在删除操作中失败。

【讨论】:

  • 当我删除播放器条目时,有什么方法可以将统计数据连同播放器一起删除?
  • 如果您希望这种情况自动发生,您可以在 FK 关系上设置“ON DELETE CASCADE”标志。或者在 Player.Delete() 方法中,您需要手动删除所有相关的统计信息,其列表将在您的 FK 名称调用的相关实体列表中。
  • 我读过级联删除。我已经在 Player 表的 SSMS 中设置了这种类型的关系,重新创建了模型并且没有任何变化。我相信我以错误的方式设置了级联删除。
  • 在您描述的数据库第一个场景中,级联删除发生在服务器端。设置“ON DELETE CASCADE”标志后,播放器删除是否仍然失败?
  • 我已经设置了级联删除,如上面答案中的图片所示,并在 Visual Studio 中更新了模型。我是否需要做任何其他事情才能使级联删除工作?我设置级联删除的方式是否正确?
【解决方案3】:

设置 PrimaryKey 和 Foreignkey 关系:根据@Bad Dub 的建议。

【讨论】:

  • 除了在 Visual Studio 项目中我还需要做其他事情吗?
  • 不需要在 Visual Studio 项目中做任何事情。只需更新实体框架工作模型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-27
  • 2013-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多