在 .Net 中自动化 DDL

发布于 2024-09-16 01:41:47 字数 566 浏览 7 评论 0原文

我维护的产品具有自行开发的数据访问层,采用 C++/COM 编程,可与基于 Windows 的 Web 应用程序设计器一起使用,并且该产品至少已有 10 年历史。该 DAL 通过类似于数据提供程序的方式进行模块化,以便它可以为特定数据库类型生成基本 SQL 和 DDL。

在迁移分析的过程中,我发现功能上最大的差距是DDL生成。使用当前产品,用户创建/删除数据输入表单,然后“即时”创建或删除数据输入字段以及适当的数据库表和字段(字段不能更改)。然而,外键关系是“软”的,仅在代码级别强制执行。

通过我迄今为止的研究,出于安全和数据完整性原因,这种方法似乎并未受到高度重视。这可能就是我找不到任何具有相同功能的工具/ORM 的原因。

我尝试过 nHibernate,它包含我需要的 SchemaUpdate 功能的一半,但只进行非破坏性架构更新。我已经检查了处理动态模式的其他方法(例如 xml 列),但这使数据检索和报告等其他因素变得非常复杂。

我的问题范围相当大,所以我不是在寻找明确的答案,只是在寻找指示。继续采用这种方法有哪些选择?是否有更好的选择来允许我不知道的动态模式?其他可能方法的基本优点和缺陷是什么?

I maintain a product that has a home-grown data access layer, programmed in C++/COM for use with a Windows-based web application designer and it is at least 10 years old. This DAL is modularized with something akin to Data Providers so that it can generate basic SQL and DDL for a specific database type.

In the process of migration analysis, the biggest gap in functionality I have found is with the DDL generation. With the current product, the user creates/deletes data input forms and then data input fields and the appropriate database tables and fields are created or deleted "on the fly" (fields cannot be altered). Foreign key relationships are "soft" however, only enforced at the code level.

Through my research so far, it seems that this approach is not highly regarded for security and data integrity reasons. Which is probably the reason I can't find any tools/ORMs that have the same functionality.

I have experimented with nHibernate, which contains half of what I need with it's SchemaUpdate functionality but only does non-destructive schema updates. I have checked out other ways of dealing with a dynamic schema such as xml columns, but this greatly complicates other factors like data retrieval and reporting.

My questions ares fairly large in scope, so I am not looking for definite answers, only pointers. What are the options for continuing forward with this approach? Are there better options for allowing a dynamic schema that I am not aware of? What are the basic advantages and pitfalls of other possible approaches?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

自由范儿 2024-09-23 01:41:47

您已将这个问题标记为“.net”,而且您说您已经尝试过 nHibernate,因此我假设您正在尝试迁移到 .NET 而远离 COM。我还猜测您正在运行 Microsoft SQL Server,尽管没有具体原因一定是这种情况(例如,软外键强制执行历来是 MySQL 的一项“功能”)。

就数据访问层的一般情况而言,实体框架可能可以为您提供帮助,但您将遇到相同类型的限制。不过,您可以做的是继续使用您提到的基于 XML 的方法,并通过与实体框架类一起工作的部分类来扩展数据模型。然后,您可以编写从 XML 列检索特定伪字段并返回它们的方法,从而帮助您的数据访问层或多或少地与应用程序的其余部分分离。

也就是说,我会仔细研究您的数据建模,看看这种动态方法是否真的有必要。您存储什么类型的数据?您能否通过实体框架 4 中的复杂类型实体来处理它?我非常确定,重新审视应用程序的数据建模和业务需求将产生一种比动态模式更规范化的方法。

You have tagged this question ".net", plus you say you have experimented with nHibernate, so I'm making the leap to assume that you are trying to migrate toward .NET and away from COM. I am also guessing that you are running Microsoft SQL Server, though there is no specific reason that this must be the case (soft foreign key enforcement was historically a MySQL "feature," for example).

Entity Framework can probably help you as far as a data access layer goes generally, but you will run into the same sorts of restrictions. What you possibly could do, though, is go ahead with the XML-based approach you were mentioning and extend the data models by way of partial classes that work alongside the Entity Framework classes. You could, then, write methods that would retrieve particular pseudo-fields from the XML column and return them, helping your data access layer to be more-or-less separated from the rest of your application.

That said, I would take a good look at your data modeling and see whether this dynamic approach is really even necessary. What kinds of data are you storing? Could you handle it through, say, Complex Type Entities in Entity Framework 4? I'm pretty sure that a fresh look at the data modeling and business requirements of your application will yield a way to do something more normalized than a dynamic schema.

真心难拥有 2024-09-23 01:41:47

我也面临着类似的困境,即将开发环境中所做的更改迁移到登台,然后迁移到生产。
我正在处理的应用程序需要频繁修改,在上次角色升级后不久就到了下一次角色升级的时间。
如果您使用的是 SQL 2005 或更高版本,那么您的处境会更好。
这是我的想法。
在源数据库上实现 DDL 触发器,跟踪 DDL 语句并将其记录到服务器实例中的单独数据库中,例如:

    Create trigger [DDLTRack]
ON Database for

CREATE_ASSEMBLY         ,ALTER_ASSEMBLY         ,DROP_ASSEMBLY
,CREATE_ASYMMETRIC_KEY  ,ALTER_ASYMMETRIC_KEY   ,DROP_ASYMMETRIC_KEY
                        --,ALTER_AUTHORIZATION
                        ,ALTER_AUTHORIZATION_DATABASE 
,CREATE_CERTIFICATE     ,ALTER_CERTIFICATE      ,DROP_CERTIFICATE
,CREATE_CONTRACT                                ,DROP_CONTRACT          
--,ADD_COUNTER_SIGNATURE                            
--,DROP_COUNTER_SIGNATURE
--,CREATE_CREDENTIAL        ,ALTER_CREDENTIAL       ,DROP_CREDENTIAL
                                                                ,GRANT_DATABASE ,DENY_DATABASE  ,REVOKE_DATABASE
,CREATE_DEFAULT                                 ,DROP_DEFAULT
                                                                ,BIND_DEFAULT   --,UNBIND_DEFAULT   
,CREATE_EVENT_NOTIFICATION                      ,DROP_EVENT_NOTIFICATION
,CREATE_EXTENDED_PROPERTY   --,ALTER_EXTENDED_PROPERTY  
,DROP_EXTENDED_PROPERTY  
,CREATE_FULLTEXT_CATALOG    ,ALTER_FULLTEXT_CATALOG ,DROP_FULLTEXT_CATALOG  
--,CREATE_FULLTEXT_INDEX        ,ALTER_FULLTEXT_INDEX   ,DROP_FULLTEXT_INDEX 
,CREATE_FUNCTION            ,ALTER_FUNCTION         ,DROP_FUNCTION
--,CREATE_INDEX             ,ALTER_INDEX            ,DROP_INDEX
--,CREATE_MASTER_KEY            ,ALTER_MASTER_KEY       ,DROP_MASTER_KEY
,CREATE_MESSAGE_TYPE        ,ALTER_MESSAGE_TYPE     ,DROP_MESSAGE_TYPE
,CREATE_PARTITION_FUNCTION  ,ALTER_PARTITION_FUNCTION   ,DROP_PARTITION_FUNCTION
,CREATE_PARTITION_SCHEME    ,ALTER_PARTITION_SCHEME     ,DROP_PARTITION_SCHEME
,CREATE_PLAN_GUIDE          ,ALTER_PLAN_GUIDE           ,DROP_PLAN_GUIDE 
,CREATE_PROCEDURE           ,ALTER_PROCEDURE            ,DROP_PROCEDURE
,CREATE_QUEUE               ,ALTER_QUEUE                ,DROP_QUEUE
,CREATE_REMOTE_SERVICE_BINDING  ,ALTER_REMOTE_SERVICE_BINDING   ,DROP_REMOTE_SERVICE_BINDING
--,CREATE_SPATIAL_INDEX                                                                 
--  ,RENAME   
,CREATE_ROLE                ,ALTER_ROLE                 ,DROP_ROLE  
--,ADD_ROLE_MEMBER                                      ,DROP_ROLE_MEMBER
,CREATE_ROUTE               ,ALTER_ROUTE                ,DROP_ROUTE
,CREATE_RULE                                            ,DROP_RULE              
                                                                                            ,BIND_RULE  ,UNBIND_RULE 
,CREATE_SCHEMA              ,ALTER_SCHEMA               ,DROP_SCHEMA
,CREATE_SERVICE             ,ALTER_SERVICE              ,DROP_SERVICE
--,ALTER_SERVICE_MASTER_KEY                 
--,BACKUP_SERVICE_MASTER_KEY    
--,RESTORE_SERVICE_MASTER_KEY
--,ADD_SIGNATURE                                            ,DROP_SIGNATURE

--,CREATE_STATISTICS                                        ,DROP_STATISTICS                    ,UPDATE_STATISTICS
--,CREATE_SYMMETRIC_KEY     ,ALTER_SYMMETRIC_KEY        ,DROP_SYMMETRIC_KEY
,CREATE_SYNONYM                                         ,DROP_SYNONYM
,CREATE_TABLE               ,ALTER_TABLE                ,DROP_TABLE
,CREATE_TRIGGER             ,ALTER_TRIGGER              ,DROP_TRIGGER
,CREATE_TYPE                                            ,DROP_TYPE
,CREATE_USER                ,ALTER_USER                 ,DROP_USER 
,CREATE_VIEW                ,ALTER_VIEW                 ,DROP_VIEW
,CREATE_XML_INDEX           
,CREATE_XML_SCHEMA_COLLECTION   ,ALTER_XML_SCHEMA_COLLECTION    ,DROP_XML_SCHEMA_COLLECTION


as 
insert ddlTracking..ddlLog(TSQL,SchemaName,ObjectName,ObjectType,eventXML,LoginName,dbName,EventType)
Select EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)')
       ,EVENTDATA().value('(/EVENT_INSTANCE/SchemaName)[1]','nvarchar(max)')
       ,EVENTDATA().value('(/EVENT_INSTANCE/ObjectName)[1]','nvarchar(max)')
       ,EVENTDATA().value('(/EVENT_INSTANCE/ObjectType)[1]','nvarchar(max)')
       ,EVENTDATA()
       ,EVENTDATA().value('(/EVENT_INSTANCE/LoginName)[1]','nvarchar(max)')
       ,EVENTDATA().value('(/EVENT_INSTANCE/DatabaseName)[1]','nvarchar(max)')
       ,EVENTDATA().value('(/EVENT_INSTANCE/EventType)[1]','nvarchar(max)')






GO

SET ANSI_NULLS OFF
GO

SET QUOTED_IDENTIFIER OFF
GO

DISABLE TRIGGER [DDLTRack] ON DATABASE
GO

ENABLE TRIGGER [DDLTRack] ON DATABASE
GO

这将在(本例)DDlTrack.dbo.DDLlog 表中进行所有更改


然后,您可以通过筛选源数据库中所需的条目来对对数据库对象所做的最后修改进行分组,并将它们应用到目标。
HTH。

I am too faced with similar dilemma of migrating changes done on development environment to staging and then production.
The application(s) I am dealing with demands frequent modification and soon after last role-up it is time for next.
If you are in SQL 2005 or above, you are in better place..
Here is what I have come up with.
Implement a DDL Trigger on your source database that tracks and log DDL statements into seperate database in the Server instance such as:

    Create trigger [DDLTRack]
ON Database for

CREATE_ASSEMBLY         ,ALTER_ASSEMBLY         ,DROP_ASSEMBLY
,CREATE_ASYMMETRIC_KEY  ,ALTER_ASYMMETRIC_KEY   ,DROP_ASYMMETRIC_KEY
                        --,ALTER_AUTHORIZATION
                        ,ALTER_AUTHORIZATION_DATABASE 
,CREATE_CERTIFICATE     ,ALTER_CERTIFICATE      ,DROP_CERTIFICATE
,CREATE_CONTRACT                                ,DROP_CONTRACT          
--,ADD_COUNTER_SIGNATURE                            
--,DROP_COUNTER_SIGNATURE
--,CREATE_CREDENTIAL        ,ALTER_CREDENTIAL       ,DROP_CREDENTIAL
                                                                ,GRANT_DATABASE ,DENY_DATABASE  ,REVOKE_DATABASE
,CREATE_DEFAULT                                 ,DROP_DEFAULT
                                                                ,BIND_DEFAULT   --,UNBIND_DEFAULT   
,CREATE_EVENT_NOTIFICATION                      ,DROP_EVENT_NOTIFICATION
,CREATE_EXTENDED_PROPERTY   --,ALTER_EXTENDED_PROPERTY  
,DROP_EXTENDED_PROPERTY  
,CREATE_FULLTEXT_CATALOG    ,ALTER_FULLTEXT_CATALOG ,DROP_FULLTEXT_CATALOG  
--,CREATE_FULLTEXT_INDEX        ,ALTER_FULLTEXT_INDEX   ,DROP_FULLTEXT_INDEX 
,CREATE_FUNCTION            ,ALTER_FUNCTION         ,DROP_FUNCTION
--,CREATE_INDEX             ,ALTER_INDEX            ,DROP_INDEX
--,CREATE_MASTER_KEY            ,ALTER_MASTER_KEY       ,DROP_MASTER_KEY
,CREATE_MESSAGE_TYPE        ,ALTER_MESSAGE_TYPE     ,DROP_MESSAGE_TYPE
,CREATE_PARTITION_FUNCTION  ,ALTER_PARTITION_FUNCTION   ,DROP_PARTITION_FUNCTION
,CREATE_PARTITION_SCHEME    ,ALTER_PARTITION_SCHEME     ,DROP_PARTITION_SCHEME
,CREATE_PLAN_GUIDE          ,ALTER_PLAN_GUIDE           ,DROP_PLAN_GUIDE 
,CREATE_PROCEDURE           ,ALTER_PROCEDURE            ,DROP_PROCEDURE
,CREATE_QUEUE               ,ALTER_QUEUE                ,DROP_QUEUE
,CREATE_REMOTE_SERVICE_BINDING  ,ALTER_REMOTE_SERVICE_BINDING   ,DROP_REMOTE_SERVICE_BINDING
--,CREATE_SPATIAL_INDEX                                                                 
--  ,RENAME   
,CREATE_ROLE                ,ALTER_ROLE                 ,DROP_ROLE  
--,ADD_ROLE_MEMBER                                      ,DROP_ROLE_MEMBER
,CREATE_ROUTE               ,ALTER_ROUTE                ,DROP_ROUTE
,CREATE_RULE                                            ,DROP_RULE              
                                                                                            ,BIND_RULE  ,UNBIND_RULE 
,CREATE_SCHEMA              ,ALTER_SCHEMA               ,DROP_SCHEMA
,CREATE_SERVICE             ,ALTER_SERVICE              ,DROP_SERVICE
--,ALTER_SERVICE_MASTER_KEY                 
--,BACKUP_SERVICE_MASTER_KEY    
--,RESTORE_SERVICE_MASTER_KEY
--,ADD_SIGNATURE                                            ,DROP_SIGNATURE

--,CREATE_STATISTICS                                        ,DROP_STATISTICS                    ,UPDATE_STATISTICS
--,CREATE_SYMMETRIC_KEY     ,ALTER_SYMMETRIC_KEY        ,DROP_SYMMETRIC_KEY
,CREATE_SYNONYM                                         ,DROP_SYNONYM
,CREATE_TABLE               ,ALTER_TABLE                ,DROP_TABLE
,CREATE_TRIGGER             ,ALTER_TRIGGER              ,DROP_TRIGGER
,CREATE_TYPE                                            ,DROP_TYPE
,CREATE_USER                ,ALTER_USER                 ,DROP_USER 
,CREATE_VIEW                ,ALTER_VIEW                 ,DROP_VIEW
,CREATE_XML_INDEX           
,CREATE_XML_SCHEMA_COLLECTION   ,ALTER_XML_SCHEMA_COLLECTION    ,DROP_XML_SCHEMA_COLLECTION


as 
insert ddlTracking..ddlLog(TSQL,SchemaName,ObjectName,ObjectType,eventXML,LoginName,dbName,EventType)
Select EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)')
       ,EVENTDATA().value('(/EVENT_INSTANCE/SchemaName)[1]','nvarchar(max)')
       ,EVENTDATA().value('(/EVENT_INSTANCE/ObjectName)[1]','nvarchar(max)')
       ,EVENTDATA().value('(/EVENT_INSTANCE/ObjectType)[1]','nvarchar(max)')
       ,EVENTDATA()
       ,EVENTDATA().value('(/EVENT_INSTANCE/LoginName)[1]','nvarchar(max)')
       ,EVENTDATA().value('(/EVENT_INSTANCE/DatabaseName)[1]','nvarchar(max)')
       ,EVENTDATA().value('(/EVENT_INSTANCE/EventType)[1]','nvarchar(max)')






GO

SET ANSI_NULLS OFF
GO

SET QUOTED_IDENTIFIER OFF
GO

DISABLE TRIGGER [DDLTRack] ON DATABASE
GO

ENABLE TRIGGER [DDLTRack] ON DATABASE
GO

This will i all your changes

in (this case) DDlTrack.dbo.DDLlog table..
You can then group last modification done to a database object by sifting the required entries in the Source database and apply them to the Target.
HTH.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文