SqlServer与MongoDB结合使用NHibernate

Program.cs代码内容:

  class Program
    {
        private const string SqlServerConnectionString =
            @"Data Source=.;Initial Catalog=SqlWithMongo;Persist Security Info=True;User ID=sa;Password=123456";

        private const string MongoConnectionString = "mongodb://localhost:27017";
        private const int NumberOfNodes = 1000;

        private static void Main(string[] args)
        {
            Console.WriteLine("Clearing database...");
            ClearDatabases();
            Initer.Init(SqlServerConnectionString, MongoConnectionString);
            Console.WriteLine("Completed");

            Console.WriteLine("Creating nodes...");
            //创建sqlserver的Node节点
            CreateNodes();
            Console.WriteLine("Completed");

            Console.WriteLine("Linking nodes...");
            long milliseconds1 = LinkSqlNodes(); //创建sqlserver的LinkNode节点
            Console.WriteLine("SQL : " + milliseconds1);
            long milliseconds2 = LinkMongoNodes(); //同时创建Node,LinkNode节点
            Console.WriteLine("Mongo : " + milliseconds2);
            Console.WriteLine("Completed");

            Console.WriteLine("Fetching nodes...");
            long milliseconds3 = FetchSqlNodes(); //取出sqlserver节点数据
            Console.WriteLine("SQL : " + milliseconds3);
            long milliseconds4 = FetchMongoNodes(); //取出Mongodb节点数据
            Console.WriteLine("Mongo : " + milliseconds4);
            Console.WriteLine("Completed");

            Console.ReadKey();
        }


        private static long FetchMongoNodes()
        {
            var stopwatch = new Stopwatch();
            stopwatch.Start();

            for (int i = 0; i < NumberOfNodes; i++)
            {
                using (var unitOfWork = new UnitOfWork())
                {
                    var repository = new MongoNodeRepository(unitOfWork);

                    MongoNode node = repository.GetById(i + 1);
                    IReadOnlyList<NodeLink> links = node.Links;
                }
            }
            stopwatch.Stop();
            return stopwatch.ElapsedMilliseconds;
        }


        private static long FetchSqlNodes()
        {
            var stopwatch = new Stopwatch();
            stopwatch.Start();

            for (int i = 0; i < NumberOfNodes; i++)
            {
                using (var unitOfWork = new UnitOfWork())
                {
                    var repository = new NodeRepository(unitOfWork);

                    Node node = repository.GetById(i + 1);
                    IReadOnlyList<Node> links = node.Links;
                }
            }

            stopwatch.Stop();
            return stopwatch.ElapsedMilliseconds;
        }


        private static long LinkSqlNodes()
        {
            var stopwatch = new Stopwatch();
            stopwatch.Start();

            using (var unitOfWork = new UnitOfWork())
            {
                var repository = new NodeRepository(unitOfWork);

                IList<Node> nodes = repository.GetAll();
                foreach (Node node1 in nodes)
                {
                    foreach (Node node2 in nodes)
                    {
                        node1.AddLink(node2);
                    }
                }
                unitOfWork.Commit();
            }

            stopwatch.Stop();
            return stopwatch.ElapsedMilliseconds;
        }


        private static long LinkMongoNodes()
        {
            var stopwatch = new Stopwatch();
            stopwatch.Start();

            using (var unitOfWork = new UnitOfWork())
            {
                var repository = new MongoNodeRepository(unitOfWork);

                IList<MongoNode> nodes = repository.GetAll();
                foreach (MongoNode node1 in nodes)
                {
                    foreach (MongoNode node2 in nodes)
                    {
                        node1.AddLink(node2);
                    }
                }
                unitOfWork.Commit();
            }

            stopwatch.Stop();
            return stopwatch.ElapsedMilliseconds;
        }


        private static void CreateNodes()
        {
            using (var unitOfWork = new UnitOfWork())
            {
                var repository = new NodeRepository(unitOfWork);

                for (int i = 0; i < NumberOfNodes; i++)
                {
                    var node = new Node("Node " + (i + 1)); //实例化 构造函数初始化name
                    repository.Save(node);
                }

                unitOfWork.Commit();
            }

            using (var unitOfWork = new UnitOfWork())
            {
                var repository = new MongoNodeRepository(unitOfWork);

                for (int i = 0; i < NumberOfNodes; i++)
                {
                    var node = new MongoNode("Node " + (i + 1));
                    repository.Save(node);
                }

                unitOfWork.Commit();
            }
        }

        //清空数据
        private static void ClearDatabases()
        {
            new MongoClient(MongoConnectionString)
                .GetDatabase("sqlWithMongo")
                .DropCollectionAsync("links")
                .Wait();

            string query = "DELETE FROM [dbo].[MongoNode];" +
                           "DELETE FROM [dbo].[Node_Node];" +
                           "DELETE FROM [dbo].[Node];" +
                           "UPDATE [dbo].[Ids] SET [NextHigh] = 0";

            using (var connection = new SqlConnection(SqlServerConnectionString))
            {
                var command = new SqlCommand(query, connection)
                {
                    CommandType = CommandType.Text
                };

                connection.Open();
                command.ExecuteNonQuery();
            }
        }
    }
相关辅助类代码如下:
  public static class Initer
    {
        public static void Init(string sqlServerConnectionString, string mongoConnectionString)
        {
            //SqlServer初始化
            SessionFactory.Init(sqlServerConnectionString);
            //Mongodb初始化
            NodeLinkRepository.Init(mongoConnectionString);
        }
    }
 public static class SessionFactory  //工厂
    {
        private static ISessionFactory _factory;


        internal static ISession OpenSession()
        {
            return _factory.OpenSession(new Interceptor());
        }


        internal static void Init(string connectionString)
        {
            _factory = BuildSessionFactory(connectionString);
        }


        private static ISessionFactory BuildSessionFactory(string connectionString)
        {
            //用编程的方式进行配置,让你能更好的理解,不需要编写复杂的映射文件,它能完全替换NHibernate的映射文件,让你在映射的时候能使用C#的强类型方式。
            FluentConfiguration configuration = Fluently.Configure()
                .Database(MsSqlConfiguration.MsSql2012.ConnectionString(connectionString))
                .Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()))
                .ExposeConfiguration(x =>
                {
                    x.EventListeners.PostLoadEventListeners = new IPostLoadEventListener[]
                    {
                        new EventListener()
                    };
                });

            return configuration.BuildSessionFactory();
        }
    }
 internal class NodeLinkRepository  //仓库 Repository模式
    {
        private static IMongoCollection<NodeLinks> _collection;


        public IList<NodeLink> GetLinks(int nodeId)
        {
            NodeLinks links = _collection.Find(x => x.Id == nodeId).SingleOrDefaultAsync().Result;
            
            if (links == null)
                return new NodeLink[0];

            return links.Links;
        }


        public Task SaveLinks(int nodeId, IEnumerable<NodeLink> links)
        {
            var nodeLinks = new NodeLinks(nodeId, links);
            var updateOptions = new UpdateOptions
            {
                IsUpsert = true
            };

            return _collection.ReplaceOneAsync(x => x.Id == nodeId, nodeLinks, updateOptions);
        }


        internal static void Init(string connectionString)
        {
            var client = new MongoClient(connectionString);
            IMongoDatabase database = client.GetDatabase("sqlWithMongo");
            var collectionSettings = new MongoCollectionSettings
            {
                WriteConcern = new WriteConcern(1)
            };
            _collection = database.GetCollection<NodeLinks>("links", collectionSettings);
        }


        private class NodeLinks
        {
            public int Id { get; private set; }
            public List<NodeLink> Links { get; private set; }


            public NodeLinks(int nodeId, IEnumerable<NodeLink> links)
            {
                Id = nodeId;
                Links = new List<NodeLink>();
                Links.AddRange(links);
            }
        }
    }
public class NodeRepository
    {
        private readonly UnitOfWork _unitOfWork;


        public NodeRepository(UnitOfWork unitOfWork)
        {
            _unitOfWork = unitOfWork;
        }


        public Node GetById(int id)
        {
            return _unitOfWork.Get<Node>(id);
        }


        public IList<Node> GetAll()
        {
            return _unitOfWork.Query<Node>()
                .ToList();
        }


        public void Save(Node mongoNode)
        {
            _unitOfWork.SaveOrUpdate(mongoNode);
        }
    }
public class MongoNodeRepository
    {
        private readonly UnitOfWork _unitOfWork;


        public MongoNodeRepository(UnitOfWork unitOfWork)
        {
            _unitOfWork = unitOfWork;
        }


        public MongoNode GetById(int id)
        {
            return _unitOfWork.Get<MongoNode>(id);
        }


        public void Save(MongoNode mongoNode)
        {
            _unitOfWork.SaveOrUpdate(mongoNode);
        }


        public IList<MongoNode> GetAll()
        {
            return _unitOfWork.Query<MongoNode>()
                .ToList();
        }
    }
模型层数据:

Node.cs,NodeMap.cs类代码如下:

 public class Node
    {
        public virtual int Id { get; protected set; }
        public virtual string Name { get; protected set; }

        protected virtual ISet<Node> LinksInternal { get; set; }
        public virtual IReadOnlyList<Node> Links
        {
            get { return LinksInternal.ToList(); }
        }


        protected Node()
        {
            LinksInternal = new HashSet<Node>();
        }


        public Node(string name)
            : this()
        {
            Name = name;
        }


        public virtual void AddLink(Node node)
        {
            LinksInternal.Add(node);
            node.LinksInternal.Add(this);
        }
    }
 public class NodeMap : ClassMap<Node>  //FluentNHibernate.Mapping.ClasslikeMapBase<T>
    {
        public NodeMap()
        {
            Id(x => x.Id, "NodeId").GeneratedBy.HiLo("[dbo].[Ids]", "NextHigh", "10", "EntityName = 'Node'");
            Map(x => x.Name).Not.Nullable();

            HasManyToMany<Node>(Reveal.Member<Node>("LinksInternal"))
                .AsSet()
                .Table("Node_Node")
                .ParentKeyColumn("NodeId1")
                .ChildKeyColumn("NodeId2");
        }
    }
MongoNode.cs和MongoNodeMap.cs的代码如下:
  public class MongoNode
    {
        public virtual int Id { get; protected set; }
        public virtual string Name { get; protected set; }

        protected virtual HashSet<NodeLink> LinksInternal { get; set; }
        public virtual IReadOnlyList<NodeLink> Links
        {
            get { return LinksInternal.ToList(); }
        }


        protected MongoNode()
        {
            LinksInternal = new HashSet<NodeLink>();
        }


        public MongoNode(string name)
            : this()
        {
            Name = name;
        }


        public virtual void AddLink(MongoNode mongoNode)
        {
            LinksInternal.Add(new NodeLink(mongoNode.Id, mongoNode.Name));
            mongoNode.LinksInternal.Add(new NodeLink(Id, Name));
        }
    }
 public class MongoNodeMap : ClassMap<MongoNode> //FluentNHibernate中的类继承
    {
        public MongoNodeMap()
        {
            Id(x => x.Id, "MongoNodeId").GeneratedBy.HiLo("[dbo].[Ids]", "NextHigh", "10", "EntityName = 'MongoNode'");
            Map(x => x.Name).Not.Nullable();
        }
    }
Utils层的类:

EventListener.cs内容:

 internal class EventListener : IPostLoadEventListener  //NHibernate.Event继承
    {
        public void OnPostLoad(PostLoadEvent ev)
        {
            var networkNode = ev.Entity as MongoNode;

            if (networkNode == null)
                return;

            var repository = new NodeLinkRepository();
            IList<NodeLink> linksFromMongo = repository.GetLinks(networkNode.Id);

            HashSet<NodeLink> links = (HashSet<NodeLink>)networkNode
                .GetType()
                .GetProperty("LinksInternal", BindingFlags.NonPublic | BindingFlags.Instance)
                .GetValue(networkNode);
            links.UnionWith(linksFromMongo);
        }
    }
  internal class Interceptor : EmptyInterceptor //NHibernate中的类
    {
        public override void PostFlush(ICollection entities)
        {
            IEnumerable<MongoNode> nodes = entities.OfType<MongoNode>();

            if (!nodes.Any())
                return;

            var repository = new NodeLinkRepository();
            Task[] tasks = nodes.Select(x => repository.SaveLinks(x.Id, x.Links)).ToArray();
            Task.WaitAll(tasks);
        }
    }
UnitOfWork.cs代码:
   public class UnitOfWork : IDisposable
    {
        private readonly ISession _session;
        private readonly ITransaction _transaction;
        private bool _isAlive = true;
        private bool _isCommitted;

        public UnitOfWork()
        {
            _session = SessionFactory.OpenSession();
            _transaction = _session.BeginTransaction(IsolationLevel.ReadCommitted);
        }


        public void Dispose()
        {
            if (!_isAlive)
                return;

            _isAlive = false;

            try
            {
                if (_isCommitted)
                {
                    _transaction.Commit();
                }
            }
            finally
            {
                _transaction.Dispose();
                _session.Dispose();
            }
        }
         
        public void Commit()
        {
            if (!_isAlive)
                return;

            _isCommitted = true;
        }


        internal T Get<T>(int id)
        {
            return _session.Get<T>(id);
        }


        internal void SaveOrUpdate<T>(T entity)
        {
            _session.SaveOrUpdate(entity);
        }


        internal IQueryable<T> Query<T>()
        {
            return _session.Query<T>();
        }
    }
Database.sql建表语句:
CREATE DATABASE [SqlWithMongo]
GO
USE [SqlWithMongo]
GO
/****** 表 [dbo].[Ids]  ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Ids](
	[EntityName] [nvarchar](100) NOT NULL,
	[NextHigh] [int] NOT NULL,
 CONSTRAINT [PK_Ids] PRIMARY KEY CLUSTERED 
(
	[EntityName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
/****** 表 [dbo].[MongoNode] ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[MongoNode](
	[MongoNodeId] [int] NOT NULL,
	[Name] [nvarchar](100) NOT NULL,
 CONSTRAINT [PK_MongoNode] PRIMARY KEY CLUSTERED 
(
	[MongoNodeId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
/******  表 [dbo].[Node] ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Node](
	[NodeId] [int] NOT NULL,
	[Name] [nvarchar](100) NOT NULL,
 CONSTRAINT [PK_NetworkNode] PRIMARY KEY CLUSTERED 
(
	[NodeId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
/******  表 [dbo].[Node_Node] ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Node_Node](
	[NodeId1] [int] NOT NULL,
	[NodeId2] [int] NOT NULL,
 CONSTRAINT [PK_NetworkNode_NetworkNode] PRIMARY KEY CLUSTERED 
(
	[NodeId1] ASC,
	[NodeId2] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
ALTER TABLE [dbo].[Node_Node]  WITH CHECK ADD  CONSTRAINT [FK_NetworkNode_NetworkNode_NetworkNode] FOREIGN KEY([NodeId1])
REFERENCES [dbo].[Node] ([NodeId])
GO
ALTER TABLE [dbo].[Node_Node] CHECK CONSTRAINT [FK_NetworkNode_NetworkNode_NetworkNode]
GO
ALTER TABLE [dbo].[Node_Node]  WITH CHECK ADD  CONSTRAINT [FK_NetworkNode_NetworkNode_NetworkNode1] FOREIGN KEY([NodeId2])
REFERENCES [dbo].[Node] ([NodeId])
GO
ALTER TABLE [dbo].[Node_Node] CHECK CONSTRAINT [FK_NetworkNode_NetworkNode_NetworkNode1]
GO

INSERT dbo.Ids (EntityName, NextHigh)
VALUES ('MongoNode', 0)
INSERT dbo.Ids (EntityName, NextHigh)
VALUES ('Node', 0)
结果如图:







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值