繁体   English   中英

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

[英]c# Entity Framework when should I use an new dbContext?

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

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

第一次连接

这个连接一直连接到同一个数据库,让我们称之为master。 它会将用户重定向到好的数据库,其中包含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";
        }

    }
}

如果有人可以帮助我正确地实例化连接,那将非常感谢谢谢

我认为你需要更好地理解db上下文的工作原理。

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

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

  • 您可以在需要使用它时创建db上下文,或者
  • 您可以将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()方法,否则数据库不会随更改一起更新。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM