您好,Hi试图找到在我们的新项目中使用的最佳性能的ORM。我的最终选择是Dapper。我们还需要使我们的应用程序至少包括以下功能,这些功能阻止我们对传递给Dapper的SQL查询进行硬编码
与数据库无关
运行时实体定义
我考虑过为Dapper写一个SQL生成器,但是我不确定我遵循的方法是最好的:
用方法签名声明一个接口。该实现对应于要使用的数据库系统(SQL Server / MySQL / PostgreSql / DB2 / Oracle /等)。
使用以下格式创建数据库XML模式:
使用上面提供的XML生成类/实体(允许在运行时扩展架构)。创建的对象是POCO。
实现在当前实体的属性上循环的方法(使用反射),并生成属性不为null的SQL语句:
String GetInsert(object currentEntity)
return:
"INSERT INTO Foo (ID, Name) VALUES (1, 'BooBoo')"
实施将至少包括
SELECT
INSERT INTO
UPDATE
DELETE
JOIN /*(using references like the KooID above)*/
WHERE /*(using filter expressions)*/
您能想到此方法的任何后退/缺点吗?您能推荐任何改进吗?
谢谢!
您是否看过dapper的contrib / rainbow部分,这些部分旨在提供自动CRUD支持(dapper的"核心"只是查询/执行)? 另外:如果它没有您需要的功能...完全有可能不是正确的选择工具。 此外,您还可以使用多种工具(对于需要密集阅读的显示页面,可以使用dapper,对于数据编辑页面,可以使用另一种ORM)
我将在这个上搭配经典的方形钉圆孔。 另外,如果您还没有看过petapoco,它就很整洁,并且带有poco生成器来处理课程。
使用MEF代替配置
如果您放弃所有这些配置并仅对这些提供程序进行硬编码并使用MEF来发现应用程序中包含哪个配置并使用该配置,该怎么办?然后,当您连接到另一个数据库时,您将编写一个新的提供程序并替换提供程序的程序集吗?然后由MEF完成其余的工作。
在生产时添加新实体而无需重新编译
但是,当您在注释中添加了更多详细信息时,我想说的是,除了我要介绍的一些更改之外,您尝试这样做的方法是:
仍然可以使用MEF来实现数据库提供程序可发现性,因此您所要做的就是将提供程序程序集拖放到bin文件夹中,然后您的应用程序将使用该程序集。当然,这也可以通过配置来完成。由您决定如何实例化正确的提供程序。
您的示例数据库架构似乎具有您自己定义的语法。也许宁愿使用已经被证明并允许标准化的定义,也可能使用更复杂的定义。
您的UI(视图或您使用的任何视图)实际上将是可以使用shcema XML而不是POCO的模板。 POCO对象只会将数据传递到UI。
由于您将在应用程序中广泛使用反射,因此可能会大大降低反射速度。我建议您使用更好的方法。在Mark Gravell的NuGet上查看此库。
生成和汇总设计时未知实体
在设计期间(从编译代码的角度来看)数据实体将是未知的,因为那些POCO将在运行时从XML模式生成。除非您的应用程序是纯粹面向数据库的(如在数据库中对表的直接操作中),否则我不会看到如何使用硬编码的UI使用这些实体?
如您所述,您的UI实际上将能够读取相同的数据模式UI并根据从数据库读取的POCO实例来填充它。只要您的应用程序完全面向数据而无需其他业务规则或用户界面流程,就可以了。
这样您将失去运行时实体定义功能。您无法猜测用户将对其进行硬编码时使用的名称。
运行时定义到底是什么意思?这是否意味着您将编辑实体配置文件并重新启动应用程序,或者会有其他添加新实体的方法吗?
我的意思是,在我的应用程序中,用户可以定义自己的数据对象类型(即实体)。我愿意将每个实体存储在单独的表上,因此,仅通过使用新的实体模式扩展XML文件,其余的将由预期的SQL生成器处理。
@MoslemBenDhaou:1.您如何在运行时创建强类型的POCO?并使用它们? 2.您如何期望在设计时由于不存在而尚未了解的现有UI消耗这些POCO? 3.我认为您的计划是在添加新实体时不重新编译您的应用程序,对吗?
1.使用动态源代码生成和编译2.将改为使用XML模式。很容易从XML模式中获取名称和属性,然后使用反射来控制POCO对象3。否和是。最终用户将添加实体而不是我,因此,我试图为每个客户端转义新产品版本
@MoslemBenDhaou:阅读我编辑过的答案。如果没有其他说明,它会提供一些信息,以避免由于性能原因而产生反射。
您提出的有关使用硬编码的UI操纵实体的要点。正如您所说,我目前的需求(第1步)几乎是数据处理或面向数据的应用程序。我将使用通用视图和流程来处理数据和触发事件。我可能需要尽快提出解决方案以适应设计。谢谢您的意见!
我提出我的解决方案,以返回最终文本:
createPROCEDURE [dbo].[Helper_CreatePocoFromTableName]
@tableName varchar(100)
AS
BEGIN
SET NOCOUNT ON;
declare @codeLines table (lineId int, lineText varchar(4000))
insert into @codeLines
Select rowNr = ROW_NUMBER() over(order by rowNr), PropertyColumn from (
SELECT 1 as rowNr, 'public class ' + @tableName + ' {' as PropertyColumn
UNION
SELECT rowNr =2 , 'public ' + a1.NewType + ' ' + a1.COLUMN_NAME + ' {get;set;}' as PropertyColumn
-- ,* comment added so that i get copy pasteable output
FROM
(
/*using top because i'm putting an order by ordinal_position on it.
putting a top on it is the only way for a subquery to be ordered*/
SELECT TOP 100 PERCENT
COLUMN_NAME,
DATA_TYPE,
IS_NULLABLE,
CASE
WHEN DATA_TYPE = 'varchar' THEN 'string'
WHEN DATA_TYPE = 'nvarchar' THEN 'string'
WHEN DATA_TYPE = 'char' THEN 'string'
WHEN DATA_TYPE = 'nchar' THEN 'string'
WHEN DATA_TYPE = 'datetime' AND IS_NULLABLE = 'NO' THEN 'DateTime'
WHEN DATA_TYPE = 'datetime' AND IS_NULLABLE = 'YES' THEN 'DateTime?'
WHEN DATA_TYPE = 'smalldatetime' AND IS_NULLABLE = 'NO' THEN 'DateTime'
WHEN DATA_TYPE = 'datetime2' AND IS_NULLABLE = 'NO' THEN 'DateTime'
WHEN DATA_TYPE = 'smalldatetime' AND IS_NULLABLE = 'YES' THEN 'DateTime?'
WHEN DATA_TYPE = 'datetime2' AND IS_NULLABLE = 'YES' THEN 'DateTime?'
WHEN DATA_TYPE = 'int' AND IS_NULLABLE = 'YES' THEN 'int?'
WHEN DATA_TYPE = 'int' AND IS_NULLABLE = 'NO' THEN 'int'
WHEN DATA_TYPE = 'smallint' AND IS_NULLABLE = 'NO' THEN 'Int16'
WHEN DATA_TYPE = 'smallint' AND IS_NULLABLE = 'YES' THEN 'Int16?'
WHEN DATA_TYPE = 'decimal' AND IS_NULLABLE = 'NO' THEN 'decimal'
WHEN DATA_TYPE = 'decimal' AND IS_NULLABLE = 'YES' THEN 'decimal?'
WHEN DATA_TYPE = 'numeric' AND IS_NULLABLE = 'NO' THEN 'decimal'
WHEN DATA_TYPE = 'numeric' AND IS_NULLABLE = 'YES' THEN 'decimal?'
WHEN DATA_TYPE = 'money' AND IS_NULLABLE = 'NO' THEN 'decimal'
WHEN DATA_TYPE = 'money' AND IS_NULLABLE = 'YES' THEN 'decimal?'
WHEN DATA_TYPE = 'bigint' AND IS_NULLABLE = 'NO' THEN 'long'
WHEN DATA_TYPE = 'bigint' AND IS_NULLABLE = 'YES' THEN 'long?'
WHEN DATA_TYPE = 'tinyint' AND IS_NULLABLE = 'NO' THEN 'byte'
WHEN DATA_TYPE = 'tinyint' AND IS_NULLABLE = 'YES' THEN 'byte?'
WHEN DATA_TYPE = 'char' THEN 'string'
WHEN DATA_TYPE = 'timestamp' THEN 'byte[]'
WHEN DATA_TYPE = 'varbinary' THEN 'byte[]'
WHEN DATA_TYPE = 'bit' AND IS_NULLABLE = 'NO' THEN 'bool'
WHEN DATA_TYPE = 'bit' AND IS_NULLABLE = 'YES' THEN 'bool?'
WHEN DATA_TYPE = 'xml' THEN 'string'
END AS NewType
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @tableName
ORDER BY ORDINAL_POSITION
) AS a1
UNION
SELECT 1000 as rowNr, '} // class ' + @tableName
) as t Order By rowNr asc
declare @max int=(select max(lineId) from @codeLines)
-- assembly result
declare @i int=1
declare @res nvarchar(max)=''
while(@i<=@max)
begin
set @res = @res +(select lineText +'
' from @codeLines l where l.lineId=@i )
set @i=@i+1
end
select classCode=@res
END