gpt4 book ai didi

c# - 是否可以在不获取所有链接的情况下获取链接表?

转载 作者:行者123 更新时间:2023-11-30 12:40:54 24 4
gpt4 key购买 nike

好的,首先我想说我正在为我的项目使用 NHibernate,在这个项目中我们有(除其他外)同步功能(从中央 MSSQL 数据库同步到本地 SQLite) .现在我知道 NHibernate 不是用来同步数据库的,但我还是想这样做。

我有一个中大型数据库模型,所以我不能在这里添加它,但问题是我有两个数据表和一个链接表来链接它们。

数据库模型:

| Product            | | ProductLinkProducer | | Producer            |
|--------------------| |---------------------| |---------------------|
| Id | | LinkId | | Id |
| Name | | Product | | Name |
| ProductLinkProducer| | Producer | | ProductLinkProducer |

数据库:

| Product | | ProductLinkProducer | | Producer |
|---------| |---------------------| |----------|
| Id | | LinkId | | Id |
| Name | | ProductId | | Name |
| | | ProducerId | | |

因此在同步期间,我首先从 Product 表复制所有数据,然后从 Producer 表复制所有数据(基本上是 var products = session.Query<Products>().ToList() )。这是由 NHibernate 在每个单独的语句中完成的:

select
product0_.id as id2_,
product0_.name as name2_
from
Product product0_

现在我必须从第一个 session (products.ForEach(x => session.Evict(x));) 中逐出所有项目

然后保存(products.ForEach(x => syncSession.save(x));)是每行插入一个(如预期的那样)。

因此,当在链接表中保存数据时,我希望也只有一个选择。然而事实并非如此。因为首先它生成一个 select ...如上。但是现在,在要插入的每一行之前,它会为产品和生产者做更多的选择

所以它看起来像这样:

产品:

  • 选择
  • 插入(id 1)
  • 插入(id 2)

制作人:

  • 选择
  • 插入(id 101)
  • 插入(id 102)

ProdLinkProducer:

  • 选择
  • 从产品中选择 id 1
  • 从产品中选择 id 1
  • 从生产者中选择 id 101
  • 从产品中选择 id 2
  • 从产品中选择 id 2
  • 从生产者中选择 id 102
  • 从生产者中选择 id 102
  • 插入
  • 插入

那么有没有办法避免这种行为呢?

编辑

为了更好地解释我所做的事情,我创建了一个小型测试项目。可以在这里找到:https://github.com/tb2johm/NHibernateSync(我宁愿只添加一个幽灵,但我认为它可能遗漏了很多数据,抱歉...)

EDIT2

我找到了一种方法让它工作,但我不喜欢它。该解决方案的工作方式是在数据库模型中创建一个 ProductLinkProducerSync 表,该表不包含任何链接,仅包含值,并避免同步普通链接表,而仅同步“同步”表。但正如我所说,我不喜欢这个想法,因为如果我更改数据库中的任何内容,我就会在需要更新的两个地方拥有相同的数据。

最佳答案

我无法找到 NHibernate 开箱即用的方式来做你所要求的。

但是我能够通过手动将 FK 引用(代理类)重新绑定(bind)到新 session 来获得所需的行为(我想有总比没有好:)

var links = session.Query<ProductLinkProducer>().ToList(); 
links.ForEach(x => session.Evict(x));
foreach (var link in links)
{
link.Product = syncSession.Get<Product>(link.Product.Id);
link.Producer = syncSession.Get<Producer>(link.Producer.Id);
syncSession.Save(link);
}
syncSession.Flush();

这是使用 NHibernate 元数据服务的通用版本:

static IEnumerable<Action<ISession, T>> GetRefBindActions<T>(ISessionFactory sessionFactory)
{
var classMeta = sessionFactory.GetClassMetadata(typeof(T));
var propertyNames = classMeta.PropertyNames;
var propertyTypes = classMeta.PropertyTypes;
for (int i = 0; i < propertyTypes.Length; i++)
{
var propertyType = propertyTypes[i];
if (propertyType.IsAssociationType && !propertyType.IsCollectionType)
{
var propertyName = propertyNames[i];
var propertyClass = propertyType.ReturnedClass;
var propertyClassMeta = sessionFactory.GetClassMetadata(propertyClass);
yield return (session, target) =>
{
var oldValue = classMeta.GetPropertyValue(target, propertyName, EntityMode.Poco);
var id = propertyClassMeta.GetIdentifier(oldValue, EntityMode.Poco);
var newValue = session.Get(propertyClass, id);
classMeta.SetPropertyValue(target, propertyName, newValue, EntityMode.Poco);
};
}
}
}

并将其应用于您的Sync 方法:

private static void Sync<T>(string tableName, ISession session, ISession syncSession)
{
Console.WriteLine("Fetching data for ####{0}####...", tableName);
var sqlLinks = session.Query<T>();
var links = sqlLinks.ToList();
Console.WriteLine("...Done");

Console.WriteLine("Evicting data...");
links.ForEach(x => session.Evict(x));
Console.WriteLine("...Done");

Console.WriteLine("Saving data...");
var bindRefs = GetRefBindActions<T>(syncSession.SessionFactory).ToList();
foreach (var link in links)
{
foreach (var action in bindRefs) action(syncSession, link);
syncSession.Save(link);
}
Console.WriteLine("...Flushing data...");
syncSession.Flush();
Console.WriteLine("...Done");
Console.WriteLine("\n\n\n");
}

关于c# - 是否可以在不获取所有链接的情况下获取链接表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40179771/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com