带有实体框架的

时间:2016-02-05 09:59:47

标签: c# asp.net asp.net-mvc entity-framework asp.net-mvc-5

我在使用Entity Framework的ASP .NET MVC 5中处理简单的CMS。 我有一些关于MVC应用程序中并发性的问题。

首先 - 我的应用程序的公共部分(没有任何身份验证的用户部分):

  • 所有数据(帖子,类别信息,标签,文档)都存储在数据库中(使用实体)

  • 在公共区域的控制器中,只有数据读取或写入数据,而不是删除或编辑

所以我的第一个问题 - 是否有必要建立一些机制来避免公共部分的并发危险?当多个用户同时浏览我的网站时,一切都会正确吗?

然后我的管理部分(需要验证):

  • 可能有多个用户具有多个角色(但实际上只有很少的注册用户)
  • 用户可以在DB
  • 中创建/编辑/删除数据

我知道安全系统需要一些安全机制,但是你可以帮我解决这个问题吗?

我也在每个方法中使用这种模式用于DbContext,其中DB是必需的:

using (var db = new CmsContext()) { // other stuff here }

而不是在所有方法中使用的一个类变量db。这是对的吗?

非常感谢您的回答!

3 个答案:

答案 0 :(得分:2)

  

是否有必要采用一些机制来避免并发危险   在公共部分?当多个用户愿意时,一切都会正确   在同一时间浏览我的网站?

据我所知,并发性与两个人同时编辑同一记录有关。考虑到公共部分没有任何编写方法,避免使用并发机制是不可能的,也不可能。

  

我知道安全系统需要一些安全机制,   但你能帮我怎么做吗?

您可以在其他类中编写查询,例如存储库和/或服务。在谷歌搜索“存储库和服务实体框架”时,我发现了这个链接http://techbrij.com/service-layer-entity-framework-asp-net-mvc-unit-testing,这听起来非常有趣。

  

我也在每个方法中使用这种模式用于DbContext,其中DB是   必要的:

using (var db = new CmsContext()) { // other stuff here }
     

而不是在所有方法中使用的一个类变量db。这是   正确?

这是个难题。现在很难说某些事情是对还是错。有很多人,有几种不同的意见。在我看来,你的例子不是最好的方法(但这并不意味着它是不正确的)。使用存储库类时,我们通常只有一个DbContext实例。看一下这个帖子c# entity framework: correct use of DBContext class inside your repository class

希望这有帮助!

答案 1 :(得分:1)

关于用户只检索/写入数据的第一个问题,并发性不会成为问题。他们永远不会尝试同时更新/删除单个行。管理部分是另一个故事。您希望多个管理员用户同时使用该数据库,这将导致admin1抓取记录,编辑记录的条件,但是当它重新插入记录时,它已由admin2更新。有两种方法可以解决这个问题:

  1. 悲观并发:这意味着您正在对数据库的某些记录使用锁定。当一个进程正在更新某个记录时,这些行会被锁定,而其他进程无法同时编辑它们。不幸的是,实体框架不支持这一点。
  2. 乐观并发: EF支持 ,这意味着您的数据库中有一个带有rowversion的额外列。当进程尝试重新插入记录时,它将首先检查rowversion是否未更改。如果它是相同的,则插入记录。如果已更改,则会重新获取记录并再次编辑值。关于乐观并发的Msdn文档here
  3. 在您的代码模型中,您可以使用[TimeStamp]属性定义额外属性:

    [TimeStamp]
    public virtual byte[] RowVersion {get; set;}
    

    或在流畅的API中,您可以像这样映射:

    modelBuilder<MyEntity>().HasProperty(p => p.RowVersion).IsRowVersion();
    

    您还可以将整行用作'rowversion'来检查更改,但通常会使用额外的列。否则,如果您只想更新1个字段,则必须将整行发送到数据库,因为需要检查rowversion。另请注意,[TimeStamp]仅适用于字节数组,如果要使用其他类型,则必须使用[ConcurrencyCheck]属性。如果将整行用作rowversion,则必须将此属性应用于所有属性。

答案 2 :(得分:1)

首先,您应该了解并发可能导致异常的所有情况。一些常见的案例,通常是关系和合同。

  • 写作和更新:

    • 表包含一些唯一约束,因此您检查实体是否存在,并尝试创建一个实体,如果它不存在。现在两个并发操作执行检查,两者都获得空结果,并且两者都尝试创建实体。一个操作将失败并出现异常,而另一个操作获得更多运气,并首先创建实体。

    • 表包含外键:通过创建新实体,其他一些操作已删除了依赖项。结果 - 例外。

任何标量值的并发更新不会导致任何异常,但最后一个会赢。

因此,您必须考虑app / db和scenario的结构,并决定是否要采取措施防止不受控制的并发更新/写入。

你能做些什么?

public class FooService {
    private static object Obj = new object();
    public void Create(Foo foo) {
        lock (Obj) {
            // check + create
        }
    }
}

这里的问题可能是你有多个实例,因为它只是服务器级锁定。

交易

数据库锁

using (var ctx = new DbCtx) {
    ctx.Database.Connection.Open();
    using (var transaction = ctx.Database.BeginTransaction(IsolationLevel.Serializable))
    {
        try {
            // check + update
            transaction.Commit();
        }
        catch (Exception) {
            transaction.Rollback();
        }
    }
    ctx.Database.Connection.Close();
}