Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 分离的实体不会更新属性_C#_Asp.net Mvc_Entity Framework 6 - Fatal编程技术网

C# 分离的实体不会更新属性

C# 分离的实体不会更新属性,c#,asp.net-mvc,entity-framework-6,C#,Asp.net Mvc,Entity Framework 6,我有一个简单的对象,它附加了一个子实体。 更新分离的对象时,不会保存包含子对象的属性。我读了很多关于这个表单的帖子,但不明白为什么它没有更新 请参见此处更新实体的内部方法: public class HtmlContent : ITextContentItem, ICreateStamp, IEditStamp, IImmutable { // ReSharper disable once UnusedMember.Local private HtmlContent()

我有一个简单的对象,它附加了一个子实体。 更新分离的对象时,不会保存包含子对象的属性。我读了很多关于这个表单的帖子,但不明白为什么它没有更新

请参见此处更新实体的内部方法:

public class HtmlContent : ITextContentItem, ICreateStamp, IEditStamp, IImmutable
{
    // ReSharper disable once UnusedMember.Local
    private HtmlContent()
    {

    }

    public HtmlContent(string name, string description, string text, DateTime creationDate,
        DateTime? lastEditDate, ApplicationUser createdBy, ApplicationUser lastEditedBy)
    {
        this.Name = name;
        this.Description = description;
        this.Text = text;
        this.CreationDate = creationDate;
        this.LastEditDate = lastEditDate;
        this.CreatedBy = createdBy;
        this.LastEditedBy = lastEditedBy;
    }

    public HtmlContent(int id, string name, string description, string text, DateTime creationDate,
        DateTime? lastEditDate, ApplicationUser createdBy, ApplicationUser lastEditedBy)
        : this(name, description, text, creationDate, lastEditDate, createdBy, lastEditedBy)
    {
        this.Id = id;
    }

    public int Id { get; private set; }

    public string Name { get; private set; }

    public string Description { get; private set; }

    public string Text { get; private set; }

    public DateTime CreationDate { get; private set; }

    public DateTime? LastEditDate { get; private set; }

    public ApplicationUser CreatedBy { get; private set; }

    public ApplicationUser LastEditedBy { get; private set; }

    internal HtmlContent SetLastEditInfo(DateTime? lastEditDate, ApplicationUser lastEditedBy)
    {
        if ((lastEditDate.HasValue && lastEditedBy == null) || 
            (!lastEditDate.HasValue && lastEditedBy != null))
        {
            throw new InvalidOperationException($"{nameof(lastEditDate)} and {nameof(lastEditedBy)} must be used together");
        }

        return new HtmlContent(this.Id, this.Name, this.Description, this.Text, this.CreationDate, lastEditDate, this.CreatedBy, lastEditedBy);
    }

    internal HtmlContent UpdateHtmlContent(string name, string description, string text)
    {
        return new HtmlContent(this.Id, name, description, text, this.CreationDate, this.LastEditDate, this.CreatedBy, this.LastEditedBy);
    }
}
请参见此处的更新方法:

public async Task Edit(int id, string name, string description, string text)
{
    try
    {
        var content = await this.WithId(id);
        this.db.Entry(content).State = EntityState.Detached;

        var currentDate = DateTime.UtcNow;
        var lastEditedBy = this.userProvider.GetCurrentUser();

        content = content.SetLastEditInfo(currentDate, lastEditedBy);
        content = content.UpdateHtmlContent(name, description, text);

        this.db.Entry(content).State = EntityState.Modified;
        await this.db.SaveChangesAsync();
    }
    catch (System.Data.Entity.Validation.DbEntityValidationException ex)
    {
        var errors = ex.EntityValidationErrors;
        throw;
    }
}
所有其他属性都更新得很好。只有LastEditedBy未更新。在Create方法中,CreatedBy工作正常,因为它是保存到数据库中的新实体。
ApplicationUser属性在首先由代码生成的数据库中有外键。

我可能错了,因为我从未尝试过像您这样做,但我可以看到您的模型存在多个问题

一,。您的数据模型具有私有setter,并且没有无参数构造函数。 您的数据模型应该只是一组具有公共setter和getter以及无参数构造函数的属性。这允许EF代理导航属性,以便它“知道”何时设置了属性

二,。填充模型的代码位于模型本身内部。 虽然这不是一个大问题,但它不允许您在将来使用通用存储库之类的东西。所有模型都必须知道如何操纵自己,这可能会导致一些不可读的代码。查看存储库模式

三,。为导航属性定义外键 同样,虽然这不是100%重要,但它允许您设置相关实体,而无需首先从数据库中选择它们。您只需设置相关实体的Id即可

四,。不应创建新实体来设置其属性 中断EF的跟踪,也中断实体的所有引用完整性。您希望实体在其生命周期内是相同的对象。这允许在不丢失对象和任何EF跟踪的情况下修改属性

我的建议是:

public class HtmlContent
{
    public int Id { get; set; }

    public string Name { get; set; }

    public string Description { get; set; }

    public string Text { get; set; }

    public DateTime CreationDate { get; set; }

    public DateTime? LastEditDate { get; set; }

    public int CreatedById { get; set; }

    public int LastEditedById { get; set; }

    public ApplicationUser CreatedBy { get; set; }

    public ApplicationUser LastEditedBy { get; set; }
}


public HtmlContentService
{
    public async Task Edit(int id, string name, string description, string text)
    {
        try
        {
            var content = await this.WithId(id);

            // no need to detach the object if you arent disposing the context
            //this.db.Entry(content).State = EntityState.Detached; 

            var currentDate = DateTime.UtcNow;
            var lastEditedBy = this.userProvider.GetCurrentUser();

            // these methods could just be moved into this method
            this.SetLastEditInfo(content, currentDate, lastEditedBy);
            this.UpdateHtmlContent(content, name, description, text);

            this.db.Entry(content).State = EntityState.Modified;
            await this.db.SaveChangesAsync();
        }
        catch (System.Data.Entity.Validation.DbEntityValidationException ex)
        {
            var errors = ex.EntityValidationErrors;
            throw;
        }
    }

    private void SetLastEditInfo(
        HtmlContent content, 
        DateTime lastEditDate, 
        ApplicationUser lastEditedBy)
    {
        if ((lastEditDate.HasValue && lastEditedBy == null) || 
            (!lastEditDate.HasValue && lastEditedBy != null))
        {
            throw new InvalidOperationException(
                $"{nameof(lastEditDate)} and {nameof(lastEditedBy)} must be used together");
        }

        content.LastEditDate = lastEditDate;
        content.LastEditedBy = lastEditedBy;
    }

    private void UpdateHtmlContent(
        HtmlContent content, 
        string name, 
        string description, 
        string text)
    {
        content.Name = name;
        content.Description = description;
        content.Text = text;
    }
}

我可能是错的,因为我从来没有尝试过像您这样做,但我可以看到您的模型存在多个问题

一,。您的数据模型具有私有setter,并且没有无参数构造函数。 您的数据模型应该只是一组具有公共setter和getter以及无参数构造函数的属性。这允许EF代理导航属性,以便它“知道”何时设置了属性

二,。填充模型的代码位于模型本身内部。 虽然这不是一个大问题,但它不允许您在将来使用通用存储库之类的东西。所有模型都必须知道如何操纵自己,这可能会导致一些不可读的代码。查看存储库模式

三,。为导航属性定义外键 同样,虽然这不是100%重要,但它允许您设置相关实体,而无需首先从数据库中选择它们。您只需设置相关实体的Id即可

四,。不应创建新实体来设置其属性 中断EF的跟踪,也中断实体的所有引用完整性。您希望实体在其生命周期内是相同的对象。这允许在不丢失对象和任何EF跟踪的情况下修改属性

我的建议是:

public class HtmlContent
{
    public int Id { get; set; }

    public string Name { get; set; }

    public string Description { get; set; }

    public string Text { get; set; }

    public DateTime CreationDate { get; set; }

    public DateTime? LastEditDate { get; set; }

    public int CreatedById { get; set; }

    public int LastEditedById { get; set; }

    public ApplicationUser CreatedBy { get; set; }

    public ApplicationUser LastEditedBy { get; set; }
}


public HtmlContentService
{
    public async Task Edit(int id, string name, string description, string text)
    {
        try
        {
            var content = await this.WithId(id);

            // no need to detach the object if you arent disposing the context
            //this.db.Entry(content).State = EntityState.Detached; 

            var currentDate = DateTime.UtcNow;
            var lastEditedBy = this.userProvider.GetCurrentUser();

            // these methods could just be moved into this method
            this.SetLastEditInfo(content, currentDate, lastEditedBy);
            this.UpdateHtmlContent(content, name, description, text);

            this.db.Entry(content).State = EntityState.Modified;
            await this.db.SaveChangesAsync();
        }
        catch (System.Data.Entity.Validation.DbEntityValidationException ex)
        {
            var errors = ex.EntityValidationErrors;
            throw;
        }
    }

    private void SetLastEditInfo(
        HtmlContent content, 
        DateTime lastEditDate, 
        ApplicationUser lastEditedBy)
    {
        if ((lastEditDate.HasValue && lastEditedBy == null) || 
            (!lastEditDate.HasValue && lastEditedBy != null))
        {
            throw new InvalidOperationException(
                $"{nameof(lastEditDate)} and {nameof(lastEditedBy)} must be used together");
        }

        content.LastEditDate = lastEditDate;
        content.LastEditedBy = lastEditedBy;
    }

    private void UpdateHtmlContent(
        HtmlContent content, 
        string name, 
        string description, 
        string text)
    {
        content.Name = name;
        content.Description = description;
        content.Text = text;
    }
}

解决方案是在模型中创建一个外键属性。数据库中已经有一个外键,但首先使用代码生成。这样,如果存在LastEditedBy用户,则可以在构造函数中设置属性


解决方案是在模型中创建一个外键属性。数据库中已经有一个外键,但首先使用代码生成。这样,如果存在LastEditedBy用户,则可以在构造函数中设置属性


我把赌注押在理由4上。首先,谢谢你的反应。我用几乎完整的模型更新了这个问题。我删除了所有不必要的信息,如属性。我有一个私有的构造函数。我使用private set创建属性是有原因的,因为这样就不能从对象外部设置值。对象必须具有关于如何维护它的所有逻辑,而不是其他表面。因为如果你可以在一个类中更改它,那么你可以在多个类中更改它。在那之后,代码复制即将到来。我还说我的实体是分离的。这是因为我不想跟踪。我添加了一个答案和问题的解决方案。现在,对象在对象本身之外是不可变的。谢谢你为我指出了正确的方向。我把赌注押在理由4上。首先,谢谢你的反应。我用几乎完整的模型更新了这个问题。我删除了所有不必要的信息,如属性。我有一个私有的构造函数。我使用private set创建属性是有原因的,因为这样就不能从对象外部设置值。对象必须启用所有逻辑
它是如何维护的,而不是其他曲面。因为如果你可以在一个类中更改它,那么你可以在多个类中更改它。在那之后,代码复制即将到来。我还说我的实体是分离的。这是因为我不想跟踪。我添加了一个答案和问题的解决方案。现在,对象在对象本身之外是不可变的。谢谢你为我指出了正确的方向。