MVC数据访问小结 ( virtual 、 volatile)

简单写一些有关MVC公共数据处理层的使用及介绍

一个命名空间说明了一切:

namespace Opentide.DataAccess
{
    /// <summary>公共数据访问处理层
    /// 
    /// </summary>
    public class DubaiCircle : DbContext
    {
        #region 变量属性

        //DBContext为数据库连接字符串
        private DubaiCircle()
            : base("name=DBContext")
        {

        }
        
        //volatile用来保持多线程数据同步
        private volatile static DubaiCircle instanceDB = null;

        private static readonly object lockHelper = new object();

        /// <summary>
        /// 数据访问公开实例对象
        /// </summary>
        public static DubaiCircle InstanceDB
        {
            get
            {
                if (instanceDB == null)
                {
                    lock (lockHelper)
                    {
                        if (instanceDB == null)
                            instanceDB = new DubaiCircle();
                    }
                }
                return instanceDB;
            }
        }
            
        //定义虚方法对实体TR_Words进行增删改查
        public virtual DbSet<TR_Words> TR_Words { get; set; }

        public virtual DbSet<TR_DefaultDataStore> TR_DefaultDataStore { get; set; }
        #endregion


        #region 公共方法
        //在完成对派生上下文的模型的初始化后,并在该模型已锁定并用于初始化上下文之前,将调用此方法。虽然此方法的默认实现不执行任何操作,但可在派生类中重写此方法,这样便能在锁定模型之前对其进行进一步的配置。
        //modelBuilder:定义要创建的上下文的模型的生成器。
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();//移除复数表名的契约
            modelBuilder.Conventions.Remove<IncludeMetadataConvention>();//移除对MetaData表的查询验证,要不然每次都要访问EdmMetadata这个表
        }
        #endregion
    }
}
View Code

别忘了添加配置webConfig文件

<connectionStrings>
<add name="DBContext" providerName="System.Data.SqlClient" connectionString="Data Source=.; User ID=sa;Password=123; MultipleActiveResultSets=true" />
</connectionStrings>

使用:

public bool UpdateDefaultDataStore(TR_DefaultDataStore DataStore)
        {
            var list = DubaiCircle.InstanceDB.TR_DefaultDataStore.Find(DataStore.ID);
            if (list != null)
            {
                list.UserID = DataStore.UserID;
                list.Type = DataStore.Type;
                list.DataName = DataStore.DataName;
                list.DataValue = DataStore.DataValue;

                DubaiCircle.InstanceDB.SaveChanges();
                return true;
            }
            else
            {
                return false;
            }
        }

传统使用方式:

private static bool InsertToJourneyPlan(DataTable dt)
        {
            string connectionString = ConfigurationManager.ConnectionStrings["DBContext"].ConnectionString;
            using (SqlConnection destinationConnection = new SqlConnection(connectionString))
            {
                destinationConnection.Open();

         //开始存储过程
var sqlTransaction = destinationConnection.BeginTransaction(); using (SqlBulkCopy bulkCopy = new SqlBulkCopy(destinationConnection, SqlBulkCopyOptions.TableLock, sqlTransaction)) { try { bulkCopy.DestinationTableName = "IR_JourneyPlan";//要插入的表的表名 bulkCopy.ColumnMappings.Add("UserID", "UserID"); bulkCopy.ColumnMappings.Add("StoreID", "StoreID"); bulkCopy.ColumnMappings.Add("Week", "Week");

bulkCopy.BatchSize = 10000; bulkCopy.BulkCopyTimeout = 900; bulkCopy.WriteToServer(dt); sqlTransaction.Commit(); return true; } catch (Exception ex) { LogHelper.Log(ex); sqlTransaction.Rollback(); return false; } } } }

相关使用个人理解:

(1)virtual 

虚方法:说白了就是给你一个自己定义的机会,如果子类方法重写父类方法,则使用时会调用子类方法。

非虚方法:子类方法跟父类方法是两个方法,谁调用执行谁。

容易混淆的地方在于父类用了虚方法,子类new 一个同名方法还是override同名方法。new则替代父类方法,相当于非虚方法使用。

class A
    {
        public virtual void F() { Console.WriteLine("A.F"); }
    }
    class B : A
    {
        public override void F() { Console.WriteLine("B.F"); }  //重写A类中的虚方法
    }
    class C : B
    {
        new public virtual void F() { Console.WriteLine("C.F"); } //隐藏B类中重写过的方法,只剩下这里的虚方法会被显示,但被D重写。
    }
    class D : C
    {
        public override void F() { Console.WriteLine("D.F"); } //重写C类中的虚方法
    }    
static void Main(string[] args)
        {
            D d = new D();
            A a = d;
            B b = d;
            C c = d;
            a.F();  //A类中的虚方法被重写为B类中的F(),所以显示结果为BF。
            b.F();  //B类中的F()方法被调用,所以显示BF
            c.F();  //B类中的重写方法被隐藏,调用C类中的虚方法,儿虚方法被D重写,故调用D类的F(),显示结果为DF
            d.F();   //寻找基类C中的虚方法,C的基类A中的虚方法不被执行,也就说明虚方法重载只能从上一辈重载
            Console.ReadKey();
        }
View Code

详细内容请参考:http://www.cnblogs.com/knowledgesea/archive/2012/04/17/2453753.html

(2)volatile

就是为了读取最新数据。

官方解释:指示一个字段可以由多个同时执行的线程修改。

声明为 volatile 的字段不受编译器优化(假定由单个线程访问)的限制。这样可以确保该字段在任何时间呈现的都是最新的值。

     volatile 修饰符通常用于由多个线程访问但不使用 lock 语句对访问进行序列化的字段。

volatile 关键字可应用于以下类型的字段:

  • 引用类型。

  • 指针类型(在不安全的上下文中)。请注意,虽然指针本身可以是可变的,但是它指向的对象不能是可变的。换句话说,您无法声明“指向可变对象的指针”。

  • 类型,如 sbyte、byte、short、ushort、int、uint、char、float 和 bool。

  • 具有以下基类型之一的枚举类型:byte、sbyte、short、ushort、int 或 uint。

  • 已知为引用类型的泛型类型参数。

  • IntPtr 和 UIntPtr

可变关键字仅可应用于类或结构字段。不能将局部变量声明为 volatile

(3)DBContext

看到不错的使用,果断MARK,有机会试用

使用Load方法将数据放入缓存

private static void GetLocalDestinationCountWithLoad()
{
  using (var context = new BreakAwayContext())
  {
    context.Destinations.Load();
    var count = context.Destinations.Local.Count;
    Console.WriteLine("Destinations in memory: {0}", count);
  }
}

本地查询(去缓存找数据)

private static void GetLocalDestinationCount()
{
  using (var context = new BreakAwayContext())
  {
    var count = context.Destinations.Local.Count;
    Console.WriteLine("Destinations in memory: {0}", count);
  }
}

参考博文:http://www.cnblogs.com/mbailing/archive/2012/07/30/2615507.html

最后记录一下新增查询条件的心得:

对于复杂模型,后台逻辑也很复杂,尤其是报表、图表之类的,有可能一个属性表示一个集合传到前台展示,如果要对部门新增查询操作,最好在集合末尾要返回显示数据的时候加查询。当然,如果能在基础数据中加就更好了。

原文地址:https://www.cnblogs.com/FlyBKB/p/5055845.html