获取“实体类型<model>不是当前上下文的模型的一部分。”

16

我在使用ASP.NET Web API逐个更新数据库中的1列时遇到了问题。我试图查询PUT仅更新行中的一个值,而不是将其余部分设置为null。我创建了一个单独的模型在控制器外接收更新,以便我可以逐个执行操作。当我在控制器中运行这行代码 db.Entry(user).State = EntityState.Modified;时出现错误。请问有什么建议可以帮我解决这个问题吗?

这是我在put方法中使用的单独ViewModel:

namespace WebAPI.Models.ViewModels
{
    public class UserViewModel
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
}

这是我的控制器使用传入的ViewModel参数调用方法:

public HttpResponseMessage PutUser(int id, UserViewModel user)
        {
            HttpResponseMessage response;

            if (db.User.IsInRole("Admin"))
            {
                try
                {
                        db.Entry(user).State = EntityState.Modified;
                        db.SaveChanges();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!UserExists(id))
                    {
                        response = new HttpResponseMessage(HttpStatusCode.NotFound);
                        return response;
                    }
                    else
                    {
                        throw;
                    }
                }

                response = new HttpResponseMessage(HttpStatusCode.NoContent);
                return response;
            }

这是我的DBContext文件:

public partial class Entities : DbContext
    {
        public Entities()
            : base("name=Entities")
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }
        public virtual DbSet<User> Users { get; set; }
    }
}

1
你能发布一下数据库表的详细信息吗?'Entry' 调用需要主键才能知道要更新哪条记录。你的模型只有名字和姓氏。 - jwatts1980
用户表由FirstName、LastName、Email和Password组成,其中Id是主键。我正在尝试仅允许更新FirstName、LastName和Email。 - Shawn
12个回答

28

如果您的存储库需要动态访问不同的Entity Framework DbContext,这意味着访问不同的数据库时会发生这种情况。

请检查每个Entity Framework DbContext在web.config文件中的数据连接字符串。

例如:

 <add name="CRMEntities" connectionString="metadata=res://*/CRMEntities.csdl|res://*/CRMEntities.ssdl|res://*/CRMEntities.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=Your Data Source;initial catalog=CRM;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />

检查连接字符串中的元数据是否指向正确的DbContext。

在此示例中,它指向名为"CRMEntities"的demx文件。


16

错误来自于您如何初始化数据上下文db

用户对象是在一个单独的db中创建的,因此,当您尝试更新user时,当前db不知道这个user对象。

您可以通过获取用户解决它

try
{
    // or check on FirstName and LastName if you don't have a user id
    var updatedUser = db.Users.SingleOrDefault(x => x.id == id);

    updatedUser.FirstName = user.FirstName;
    updatedUser.LastName = user.LastName;

    db.Entry(updatedUser).State = EntityState.Modified;
    db.SaveChanges();
 }

或者,你可以确保用于创建user对象的数据上下文与尝试更新用户的数据上下文相同。

这对你有意义吗?


有点像哈哈。我理解了如何查找用户ID并引用该ID来存储新的FirstName和LastName,然后将更改更新到数据库中的新变量中。但是我遇到了与底部两个答案相同的类型错误,其中.FirstName和.LastName给了我“不包含定义”错误? - Shawn
我进行了一个小更新。请尝试使用var updatedUser = db.Users.SingleOrDefault(x => x.id == id);。这样你就可以确保只获取到一个实例,而不是使用Where返回查询结果,当你只需要单个用户时。 - The Jonas Persson
您是位众人之神啊,先生。问题已标记为已回答,非常感谢您。 - Shawn
这正是我的问题。我的控制器有两个 DbContext,我使用了错误的一个来标记条目为已修改。愚蠢的笔误。谢谢! - vaindil

5

请确保您的元数据部分与edmx中的部分相同。

connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;"

2

你的视图模型不是完全限定的用户对象。因此,你需要获取一个。

这个调用 db.User.IsInRole("Admin"),似乎表明你已经有了当前用户。你应该修改那个并提交更改。

try
{
    db.User.FirstName = user.FirstName;
    db.User.LastName = user.LastName;

    db.Entry(db.User).State = EntityState.Modified;
    db.SaveChanges();
}

对于这个问题,我得到了“不包含‘LastName’的定义(尽管它是数据库中的一个条目),接受类型为...的第一个参数”的错误。在db.User.后面我得到的选项是像Any、Find等等的东西... - Shawn

2

更新模型以包含ID属性。

然后执行

var e = db.Entry(user);

e.Property(p => p.FirstName).Modified = true;

属性行是指定单个字段的方法。


我遇到了一个错误,它说没有定义modified,并且找不到接受第一个参数类型为<crazy string>的扩展Modified。 - Shawn
“user” 应该是实体模型中的类型,而不是自定义模型。 - jwatts1980

1
我也遇到了这个异常。我通过右键单击图表中的Entity.edmx模型,然后通过“从数据库更新模型”刷新连接到我的数据库来解决它。
我不知道为什么这样做有效,但至少在我的情况下是如此。

1
在我的情况下,问题是相应实体文件中缺少一个列。在edmx中有一列映射,但在charp文件中不存在。

1
这是因为有人通过剪切和粘贴现有的连接字符串在app.config中创建了一个新的连接字符串,导致发生了这种情况。
结果如下所示:
<connectionStrings>
    <add
        name="Db1Context"
        connectionString="metadata=res://*/Db1Context.csdl|res://*/Db1Context.ssdl|res://*/Db1Context.msl;..."
        providerName="System.Data.EntityClient"
    />
    <add
        name="Db2Context"
        connectionString="metadata=res://*/Db1Context.csdl|res://*/Db1Context.ssdl|res://*/Db1Context.msl;..."
        providerName="System.Data.EntityClient"
    />
</connectionStrings>

请注意,Db2Context仍然在其元数据中引用了DbContext1...

0

确认服务器是64位还是32位,并重新编译应用程序。


这并没有提供问题的答案。如果要批评或请求作者澄清,请在他们的帖子下留言 - 您始终可以在自己的帖子上发表评论,并且一旦您拥有足够的声望,您将能够评论任何帖子。- 来自审查 - Ravi Y
2
@ryadavilli,它确实提供了一个答案> - Rob

0

我遇到了同样的问题,当我尝试将我的类的一个实例添加到DbSet时,收到了异常。我的问题是数据库中表的定义与我的实际对象不匹配(我的模型中缺少2个非空属性)。我将这两个属性添加到我的类中,错误就消失了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接