c#Entity Framework何时应该使用新的dbContext?

时间:2016-12-27 14:41:05

标签: c# sql database entity-framework design-patterns

我想知道一段时间创建dbcontext的新实例的正确方法是什么?我遇到了一些问题因为当我通过SQL Server在数据库中进行更改时,我的上下文不会更新数据。让我解释一下我的网站是如何运作的。

我们正在为我们的客户预约网站明确预约。我们将托管我们服务器上的所有数据库。它是如何工作的应用程序由2个连接组成:

第一次连接

此连接始终连接到同一个数据库,让我们将其称为主数据库。 它将用户重定向到具有其中url代码的良好数据库示例: 的 www.example.com/foo 服务器将检查此处 foo 的代码 因此,它会在表中查找以匹配代码,然后将好的数据库名称放在应该重定向的位置,这就是我的第二个连接来了

第二次连接

这个将根据master返回的数据建立到正确数据库的连接。从这里看起来一切似乎都很好,除了DBContext实际上永远不会更新,因为我没有正确地实例化它并且我没有丰富的经验。这是我和同事一起做的代码:

using System;
using System.Data.EntityClient;
using System.Data.SqlClient;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.Routing;
using WebRV.Models.Entities;

namespace WebRV.RouteDb
{

    public class DbConnection
    {

        private static DbConnection instance;
        private Cliniciel_WebRV_Entities db;
        private String connectionString;
        private readonly Cliniciel_WebRV_MasterEntities masterDb = new Cliniciel_WebRV_MasterEntities();
        private Int32 idCie;
        private static readonly object myLock = new object();


        private DbConnection() {
            var context = new HttpContextWrapper(System.Web.HttpContext.Current);
            var routeData = RouteTable.Routes.GetRouteData(context);
            // Use RouteData directly:
            String code = routeData.Values["code"].ToString();
            //String  code = Thread.CurrentContext. .RequestContext.RouteData.Values["code"].ToString();
            var response = masterDb.SYS_tbCustDBLocation.Where(p => p.CustDBLocationCode == code).ToList();

            if (response.Count == 1)
            {
                try
                {
                    db = CreateConnection(response.FirstOrDefault());
                    idCie = (db.SYS_vwCie.Where(p => p.ClinicielWebName == code).FirstOrDefault()).IdCie;
                }
                catch (Exception e)
                {
                    throw e;
                }

            }
            else {
                throw new FormatException();
            }
        }

        private Cliniciel_WebRV_Entities CreateConnection(SYS_tbCustDBLocation data)
        {

            connectionString = *****

            db = new Cliniciel_WebRV_Entities();

            db.Database.Connection.ConnectionString = connectionString;

            db.Database.Connection.Open();

            return db;
        }

        private static void CreateInstance() {
            instance = new DbConnection();
        }

        public static DbConnection GetInstance() {
            lock (myLock)
            {
                if (instance == null)
                {
                    CreateInstance();
                }

            }

            return instance;
        }

        public String GetConnectionString()
        {
            return connectionString;
        }

        public Cliniciel_WebRV_Entities GetConnection()
        {
            return db;
        }

        public Int32 GetIdCie()
        {
            //hard code 1 but test
            //return idCie;
            return 1;
        }

    }
}

以下是我如何使用它的一个例子:

  //[CompanyCodeFilter]
    public class HomeController : AppointementController 
    {
        //public static Cliniciel_WebRV_Entities entityDB = DbConnection.GetConnection();

        public HomeController()
        {
            base.Refresh();
        }

 public JsonResult GetConsultationDescription(Int32 idService)
        {
            //base.Refresh();
            entityDB.Set<SYS_vwService>().AsNoTracking();
            var motifDescription = entityDB.SYS_vwService.Where(s => s.IDLang == cultureName && s.IdService == idService && s.IdCie == idCie).FirstOrDefault();
            var base64 = Convert.ToBase64String(motifDescription.ServiceImage);
            var imgSrc = String.Format("data:image/gif;base64,{0}", base64);
            var imageDecode = imgSrc;
            if (base64 == "AA==")
            {
                imageDecode = "";
            }
            var result = new { motifDescription, imageDecode };


            return Json(result, JsonRequestBehavior.AllowGet);
        }
  }

这里base.refresh()调用:

using System;
using System.Linq;
using WebRV.Filters;
using WebRV.Localization;
using WebRV.Models.Entities;
using WebRV.RouteDb;

namespace WebRV.Controllers
{
    //[CompanyCodeFilter]
    public class AppointementController : BaseController
    {
        protected Cliniciel_WebRV_Entities entityDB;
        protected Int32 idCie;
        protected String cultureName;

        //public AppointementController() {
        //    Refresh();
        //}

        //Permet de bien vérifier quel DB utilisé, quel idCie et quel cultureName.
        protected void Refresh() {
            entityDB = DbConnection.GetInstance().GetConnection();
            idCie= DbConnection.GetInstance().GetIdCie();
            cultureName = CultureLocalization.GetCulture();
            //cultureName = "en-ca";
        }

    }
}

如果有人可以帮我正确地实例化连接,那么感谢你

3 个答案:

答案 0 :(得分:2)

我认为您需要更好地了解数据库上下文的工作原理。

它是许多设计模式的组合,但在基本层面上,它本质上是一个工作单元,用于跟踪表示数据的对象的更改。因此,它并不意味着被用作一直保持开放的连接,你可以只是前后移动,尽管你可以在一定程度上使用它。

从您的代码中,您似乎在ASP.NET MVC应用程序中使用它。由于应用程序的性质,您可以执行以下两项操作之一:

  • 您可以在需要使用时创建数据库上下文,或
  • 您可以将db上下文创建为控制器的属性

最后,他们有点相同。我个人会建议您在需要时使用它来创建上下文的实例,确保正确处理它。然后,您可以拥有一个基本控制器类,该类公开了为您的上下文创建实例的CreateConnetion()方法,类似于您已有的Cliniciel_WebRV_Entities CreateConnection()方法,除了您不需要打开连接显式和连接字符串可以作为构造函数参数传递,如果您添加一个分部类并为上下文实现一个。像这样:

public partial class Cliniciel_WebRV_Entities
{
    public Cliniciel_WebRV_Entities(string nameOrConnectionString):base(nameOrConnectionString)
    {

    }
}

然后您可以像这样使用它:

private Cliniciel_WebRV_Entities CreateConnection()
    {
        //Code to figure out which db to connect to (based on the other connection. You should consider caching that too if it doesn't change very often)
        var nameOrConnectionString = FigureOutConnection();
        var db = new Cliniciel_WebRV_Entities(nameOrConnectionString);
        return db;
    }

请记住,上下文取决于元数据,因此请确保您的连接字符串反映了该内容。

在你的代码中,你会像这样使用它:

public JsonResult GetConsultationDescription(Int32 idService)
        {
            using(var entityDB = CreateConnection())
            {
                var motifDescription = entityDB.SYS_vwService.Where(s => s.IDLang == cultureName && s.IdService == idService && s.IdCie == idCie).FirstOrDefault();
                var base64 = Convert.ToBase64String(motifDescription.ServiceImage);
                var imgSrc = String.Format("data:image/gif;base64,{0}", base64);
                var imageDecode = imgSrc;
                if (base64 == "AA==")
                {
                    imageDecode = "";
                }
                var result = new { motifDescription, imageDecode };


                return Json(result, JsonRequestBehavior.AllowGet);
            }
        }
  }

要记住的另一件事是咬住每个新手的事情是你不应该将实体(来自上下文的对象)传递给模型中的视图。这是因为一旦处理了上下文,具有导航属性的对象就会中断。有办法绕但不推荐。将对象映射到模型。

顺便说一下,不要忘记在修改实体后调用SaveChanges()方法,否则数据库不会随更改而更新。

答案 1 :(得分:0)

答案 2 :(得分:0)

当您将DbContext传递给服务或业务类时,您将其作为值传递而不是作为引用,因此您将丢失在客户端代码中所做的所有更改,选项是将其作为引用传递但是它不安全而不是一个好的做法但是,如果您将上下文作为委托传递,则直接传递对象的引用,以便最好的方法是为了保持注入的上下文与业务/服务层的更改。 这是一个想法:
选项1,将其作为参考传递,不建议使用:

 public void Call()
    {
        //Attach changes to context, Passing as reference
        Process(ref _context);
        //All changes attached to context
        _context.SaveChanges();
    }

    public void Process(ref Cliniciel_WebRV_MasterEntities context)
    {
        var c = context();
        //Get entites dbcontext
        //Update entites
    }

选项2,将其作为代表传递,最佳approch:

public void Call()
    {
        //Attach changes to context, Passing as reference
        Process(() => _context);
        //All changes attached to context
        _context.SaveChanges();
    }

    public void Process(Func<Cliniciel_WebRV_MasterEntities> context)
    {
        var c = context();
        //Get entites dbcontext
        //Update entites
    }