这几天,在博客园看到了很多朋友的 ORM,忍不住也把我写的 ORM 拉出来溜溜,我写的这款 ORM 叫 ALinq 。
1、什么是 ALinq ?
ALinq 是一款与 Linq to SQL 相兼容的 ORM。简而言之,就是 Linq to SQL 的山寨版,并且青出于蓝,胜于蓝。它不但完整实现了 Linq to SQL 的功能,并在其基础上进行了一系列的扩展。
API 的改进:
1、支持多种数据库,包括 MSSQL2000,20005,Access,SQLite,MySQL,Oracle,与 Friebird 。
3、增加了 DataContext.CreateTable, DataContext.CreateForegionKey 函数。这两个函数大大方便了用户在虚拟主机上创建数据库,或者对数据库进导入。
设计器的改进:
1、允许在属性、类中添加 Attribute 特性。这大大方便了用户与第三方框架配合使用。
2、允行在属性、类中添加注释。
3、允许对实体类进行更新,例如:在数据库添加了一个新的字段,只需点一下鼠标,即可刷新。
4、可以生成 Xml 映射文件。
2、为什么要使用 ALinq ,而不是第三方 ORM ?
1、ALinq 拥用完善的设计器,与 Linq to SQL 相兼容的 API ,你无重新学习,即可上手。只要你安装好,即可懂得用了,所有 Linq to SQL 的知识都可以迁移到 ALinq 上。
2、ALinq 运行效率高,品质稳定,并且已经经过大量的用户验证,好评如潮,我们的用户遍及各行各业。
3、ALinq 是收费,收费也会成为使用的理由 ??? 是的,因为 ALinq 能收到钱,所以可以一直更新维护下去。相信我,ALinq 是绝对是款性价比极高的软件。买东西,我们都知道,可不能一味追求便宜。其实软件也是这样,免费、开源的东西,用在项目里,绝对会让人发狂。你可能会说,拥有代码,碰到问题可以自行修改,这只不过是理论上的罢了,实际上绝大部份的人都是不可能做到的,不信你把 DBLinq 里的 BUG 都给修正,事实 ALinq 有很多用户都是从 DBLinq 转过来的。
3、发展线路图
* 增强对 Ado.net data service 增、删、改操作的支持。
* ALinq:支持 HQL 或 ESQL 查询。
* ALinq:支持多表继承与以及多对多关联。
* ORDesigner:实现从模型更新数据库。
* ORDesigner:集成数据库设计。
* ORDesigner:集成数据验证的代码生成。
* ORDesigner:Ado.net data service 代码生成。
* ORDesigner:支持 Visual Studio 2010。
ALinq 可以秒杀 Linq to SQL, Entity Framework ? 你是不是觉得我在吹牛呢?是驴是马,拉出溜溜就知道。
请各位看官到 http://cn.alinq.org 下载试用,好不好用,你来评价。如果你下载了,发现不好用,尽管来踢场好了。
使用 ALinq 支持多种数据库
1、打开设计器,生成实体类,然后在 External Mapping 属性中,选择 true。Connection 属性中的 Application Setting 设为 true, 然后保存重新生成代码,你会发现多了一个后缀名为 .designer.map 的 Xml 文件 。
生成 Xml 映射文件(局部)
2、在代码中使用 XmlMapping
public Database()
: base(WebConfigurationManager.ConnectionStrings["ALinqBBS"].ConnectionString, CreateMappingSource())
{
}
public Database(string connn)
: base(connn, CreateMappingSource())
{
}
static XmlMappingSource CreateMappingSource()
{
var xmlMapping = XmlMappingSource.FromStream(typeof(Database).Assembly.GetManifestResourceStream("ALinq.BBS.Business.Database.designer.map"));
return xmlMapping;
}
3、下面我们接着来把数据库转换成 MS SQL 数据库
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
var stream = typeof(Database).Assembly.GetManifestResourceStream("ALinq.BBS.Business.Database.designer.map");
Debug.Assert(stream != null);
var reader = new System.IO.StreamReader(stream);
//将Provider 切换为 Sql2005Provider
var xmlDatabase = XmlMappingSourceUtility.CreateFrom<Database>(reader);
xmlDatabase.Provider = "ALinq.SqlClient.Sql2005Provider, ALinq, Version=2.3.0.0, Culture=neutral, PublicKeyToken=2b23f34316d38f3a";
//修改 XmlMapping 中 SQLite 的数据类型为 SQL2005 的数据类型。如果你需要导入数据,并且含还有自增长列,你还得设 DbGenerate 为 false 。
var xmlColumn = xmlDatabase.Type(o => o.Posts).Column(o => o.Content);
xmlColumn.DbType = "Text";
xmlColumn = xmlDatabase.Type(o => o.Replies).Column(o => o.Content);
xmlColumn.DbType = "Text";
//下面的是 SQL2005 数据库
var conn = @"Data Source=VPC1\SQLEXPRESS;Initial Catalog=ALinqBBS;User ID=sa;Password=test";
var db = new Database(conn, XmlMappingSource.FromXml(xmlDatabase.Element.ToString())) { Log = Console.Out };
var sqlLiteDb = new Database(@"C:\ALinqBBS.db3", XmlMappingSource.FromStream(typeof(Database).Assembly.GetManifestResourceStream("ALinq.BBS.Business.Database.designer.map"))) { Log = Console.Out };
//如查你不需要导入数据库,直接生成数据库就可以了。代码如下:
//if (db.DatabaseExists())
// db.DeleteDatabase();
//db.CreateDatabase();
//如查你需要导入数据库,请参考下面的代码。
var tables = db.Mapping.GetTables();
foreach (var table in tables)
{
//在数据库中创建表
if (db.TableExists(table))
db.DeleteTable(table);
db.CreateTable(table);
}
//导入数据库 开始
foreach (var board in sqlLiteDb.Boards.ToList())
db.Boards.Insert(board);
foreach (var post in sqlLiteDb.Posts.ToList())
db.Posts.Insert(post);
foreach (var reply in sqlLiteDb.Replies.ToList())
db.Replies.Insert(reply);
foreach (var user in sqlLiteDb.Users.ToList())
{
var date = DateTime.Parse("1900-1-1");
if (user.CreationDate < date)
user.CreationDate = date;
db.Users.Insert(user);
}
foreach (var topPost in sqlLiteDb.TopPosts.ToList())
db.TopPosts.Insert(topPost);
foreach (var item in sqlLiteDb.PostFavors)
db.PostFavors.Insert(item);
foreach (var item in sqlLiteDb.ObjectIdentities)
db.ObjectIdentities.Insert(item);
//导入数据库 结束
//创建关联
foreach (var table in tables)
{
db.CreateForeignKeys(table);
}
}
}
class XMappingDatabase<T>
{
public XMappingDatabase(XElement element)
{
this.Element = element;
}
public XElement Element { get; private set; }
public string Provider
{
get
{
var attribute = Element.Attribute("Provider");
if (attribute == null)
return null;
return attribute.Value;
}
set
{
var attribute = Element.Attribute("Provider");
if (attribute == null)
Element.SetAttributeValue("Provider", value);
else
attribute.Value = value;
}
}
}
class XMappingType<T>
{
public XMappingType(XElement element)
{
this.Element = element;
}
public XElement Element { get; private set; }
}
class XMappingColumn
{
public XMappingColumn(XElement element)
{
this.Element = element;
}
public XElement Element { get; private set; }
public string DbType
{
get
{
var attribute = Element.Attribute("DbType");
if (attribute == null)
return null;
return attribute.Value;
}
set
{
var attribute = Element.Attribute("DbType");
if (attribute == null)
Element.SetAttributeValue("DbType", value);
else
attribute.Value = value;
}
}
}
static class XmlMappingSourceUtility
{
public static XMappingType<TEntity> Type<TSource, TEntity>(this XMappingDatabase<TSource> source, Expression<Func<TSource, Table<TEntity>>> predicate) where TEntity : class
{
var name = typeof(TEntity).FullName;
var element = source.Element.Descendants().Where(o => o.Name.LocalName == "Type")
.Where(o => o.Attribute("Name") != null && o.Attribute("Name").Value == name).SingleOrDefault();
if (element == null)
throw new Exception(string.Format("Count Not Found the '{0}' Element in the XDocument", name));
return new XMappingType<TEntity>(element);
}
public static XMappingColumn Column<TSource>(this XMappingType<TSource> source, Expression<Func<TSource, object>> predicate)
{
var parameters = predicate.Parameters;
var name = ((MemberExpression)predicate.Body).Member.Name;
var element = source.Element.Descendants().Where(o => o.Name.LocalName == "Column")
.Where(o => o.Attribute("Name") != null && o.Attribute("Name").Value == name).SingleOrDefault();
if (element == null)
throw new Exception(string.Format("Count Not Found the '{0}' Element in the XDocument", name));
return new XMappingColumn(element);
}
public static XMappingDatabase<TSource> CreateFrom<TSource>(StreamReader reader)
{
var doc = XElement.Load(reader, LoadOptions.None);
return new XMappingDatabase<TSource>(doc);
}
}
}
[ORDesigner] 自动编号属性的设置
选择要设置为自动编号的属性,例如:UserID。然后将 Auto Generated 设置为 true,Auto-Sync 设置为 OnInsert 。
[ORDesigner] 自定义数据库连接自符串
很多时候,我们都需要从配置文件中读取数据库连接自符串,但是 ORDesigner 生成 DataContext 的初始化函数是写死的。
public MyDataContext(ALinq.Mapping.MappingSource mappingSource) :
base("data source=C:\\Northwind.db", mappingSource)
{
OnCreated();
}
其实我们只要设置一下就行了,就不会生成上面的初始化函数了。将 Application Settings 由 false 改为 true 。
ALinq(V2.2) 双主键关联 Bug(已修正)
这个 Bug 已经修正,但尚未发布,急需用的可以和我联系。
Is possible to create association EntitySet with multiple primary keys?
See the example:
Order
IdCompany |
PK |
IdOrder |
PK |
Number |
|
Sum |
OrderDetail
IdCompany |
FK |
IdOrder |
FK |
IdDetail |
PK |
Qtde |
|
PriceUnit |
|
Sum |
I did search on google in linq to sql references and not found something about.
I tried do the code:
[Association(Name = "ORDER_DETAILS", Storage = "_Details", ThisKey = "IdCompany,IdOrder", OtherKey = "IdCompany,IdOrder")]
Can you help me? (I have a license)