zoukankan      html  css  js  c++  java
  • C# NPOCO ORM框架使用学习(2)

    从数据库映射到现在有对象

    使用 SingleIntoSingleOrDefaultIntoFirstInto 和 FirstOrDefaultInto 方法,可以将数据库的列映射到现有对象。只有查询中的列将被设置在现有对象上。

    public class User 
    {
        public int UserId { get;set; }
        public string Email { get;set; }
    }
    
    var user = new User() { UserId = 1 };
    IDatabase db = new Database("connStringName");
    db.SingleOrDefaultInto(user, "select Email from users where userid = @0", 1);

    一对多的查询

    这帮助您映射一个与嵌套列表对象有一对多关系的查询。鉴于以下类:

    public class UserDto
    {
        public int UserId { get; set; }
        public string Name { get; set; }
        public List<CarDto> Cars { get; set; }
    }
    
    public class CarDto
    {
        public string Make { get; set; }
        public string Color { get; set; }
    }

    查询:

    IDatabase db = new Database("connStringName");
    
    //v2
    var users = db.FetchOneToMany<UserDto, CarDto>(x => x.UserId, 
        "select u.*, c.* from Users u inner join Cars c on u.UserId = c.UserId order by u.UserId");
    
    //v3
    var users = db.FetchOneToMany<UserDto>(x => x.Cars, 
        "select u.*, c.* from Users u inner join Cars c on u.UserId = c.UserId order by u.UserId");

    这将为您提供一个UserDto对象的列表,并且对于每个对象,也将填充CarDto的列表。

    注意:

    1. 此方法的第一个参数是 lambda 表达式,该表达式标识第一个对象的惟一属性。
    2. 列的顺序非常重要。它必须与定义的泛型参数的顺序一致。在这个示例中,查询指定了u。然后c * 映射到< UserDto,CarDto >。
    3. 如果您要映射到用于插入数据的对象,那么你需要确定你对 List<> 使用了 [Ignore] 属性。
    4. 如果您正在使用一个外连接来执行查询,并且您预期其中的一些将不会被填充,请确保在 FetchOneToMany 调用中使用第二个lambda。这将返回许多对象的主要属性。在上面的例子中,这可能是x = > x . carid。
    5. FetchOneToMany 不能用于获取嵌套的一对多关系,也不能用于多个一对多关系。例如,如果UserDto也有一个BoatsDto列表,那么只有CarDto列表或BoatsDto列表可以加载并映射到一个查询。

    对嵌套对象映射

    这将帮助您将查询映射到有嵌套对象的对象。鉴于以下类:

    public class User
    {
        public int UserId { get; set; }
        public string Name { get; set; }
        public Address Address { get; set; }
    }
    
    public class Address
    {
        public string Street { get; set; }
        public string City { get; set; }
    }

    查询:

    IDatabase db = new Database("connStringName");
    var users = db.Fetch<User, Address>("select u.UserId, u.Name, u.Street, u.City from Users");

    这将给您一个使用嵌套类映射的 user 对象列表。

    注意:

    1. 列的顺序非常重要。查询中的列需要按照指定的泛型参数的顺序指定。如。首先指定用户列,然后指定地址列。
    2. 如果您要映射到用于插入数据的对象,那么您需要确保使用 [ResultColumn] 属性忽略地址类。从v3中,您还需要添加[ComplexMapping]s属性。

    字典和对象数组查询

    有时,您不知道查询返回的列。这就是能够映射到字典< string,object >,或object[]的地方。字典和对象数组查询。

    var users = db.Fetch<Dictionary<string, object>>("select * from users");
    
    or
    
    var users = db.Fetch<object[]>("select * from users");

    注意:

    从NPoco版本 > 1.0.3 开始,所有数组类型(值类型。string[]、int[]、double[]、DateTime[]等)将是一个有效的通用参数。

    跟踪更改的更新

    使用快照

    快照用于跟踪实体的更改,因此只有更改的属性才会被更新。在下面的示例中,只有新 Name 将被发送到数据库,因为它的年龄值与启动快照时的值相同。

    IDatabase db = new Database("connString");
    var user = db.SingleById<User>(1);  // Name = "Ted", Age = 21
    
    var snapshot = db.StartSnapshot(user);  // 在此之后的任何更改都将被记录。
    
    user.Name = "Bobby";
    user.Age = 21;
    
    db.Update(user, snapshot.UpdatedColumns());  // 只更新Name列

    只有在UpdatedColumns()之前的更改将被包含在变更集中。

    复合主键

    复合键可以指定通过放置两个逗号之间的列名称 [PrimaryKey] 属性。

    [TableName("Users")]
    [PrimaryKey("UserId,UserName")]
    public class User
    {
        public int UserId { get; set; }
        public string UserName { get;set; }
    }

    当设置了复合键,AutoIncrement属性总是默认false

    如果你想使用 SingleById 方法查找一个对象,就可以使用匿名类型。

    IDatabase db = new Database("connStringName");
    var user = db.SingleById<User>(new {UserId = 1, UserName = "user"});

    多个结果集

    该特性使您能够在只调用一次数据库的情况下映射多个查询。

    FetchMultiple 方法返回一个  Tuple < T >,List < T1 > >。

    IDatabase db = new Database("connStringName");
    Tuple<List<User>, List<Address>> data = db.FetchMultiple<User, Address>("select * from users;select * from addresses;");
    var users = data.Item1;
    var addresses = data.Item2;

    支持:

    这仅支持可以返回多个结果集的数据库。在IDataReader上实现了NextResult()。通过Npgsql支持Sql Server和Postgresql。

    流利的映射

    对于一个类的映射,您可以使用 Map < T > 继承,其中 T 是要映射的类。

    public class UserMapping : Map<User>
    {
        public UserMapping()
        {
            PrimaryKey(x => x.UserId);
            TableName("Users");
            Columns(x =>
            {
                x.Column(y => y.Name).Ignore();
                x.Column(y => y.Age).WithName("a_ge");
            });        
        }
    }

    映射也可以从映射继承,并使用For < >方法在一次类中指定所有的映射。

    public class OurMappings : Mappings
    {
        public OurMappings()
        {
            For<User>().Columns( ....
        }
    }

    数据库工厂设置:

    您只需要创建映射一次,我们使用数据库工厂来完成此操作。

    public void Application_Start()
    {
         MyFactory.Setup();
    }
    public static class MyFactory
    {
        public static DatabaseFactory DbFactory { get; set; }
    
        public static void Setup()
        {
            var fluentConfig = FluentMappingConfiguration.Configure(new OurMappings());
            //或单个的映射 
            //var fluentConfig = FluentMappingConfiguration.Configure(new UserMapping(), ....);
    
            DbFactory = DatabaseFactory.Config(x =>
            {
                x.UsingDatabase(() => new Database("connString"));
                x.WithFluentConfig(fluentConfig);
                x.WithMapper(new Mapper());
            });
        }
    }

    然后你可以在你的代码中使用它。

    var database = MyFactory.DbFactory.GetDatabase();

    如果你使用的是容器,那么你可以使用类似的东西

    For<IDatabase>().Use(() => MyFactory.DbFactory.GetDatabase());

    简单LINQ查询

    Query<T>

    NPoco介绍了一种使用LINQ查询获取对象的简单方法。这里有一个简单的例子。

    IDatabase db = new Database("connString");
    db.Query<User>().Where(x => x.Name == "Bob")
                               .OrderBy(x => x.UserId)
                               .Limit(10, 10)
                               .ToList();

    可用的LINQ关键字:

    • ProjectTo
    • Count
    • Any
    • Where
    • OrderBy
    • OrderByDescending
    • ThenBy
    • ThenByDescending
    • Limit
    • Include
    • IncludeMany

    这里是你如何使用一个IN子句:

    var users = db.Query<User>().Where(x => new[] {1,2,3,4}.Contains(x.UserId)).ToList();
    // 或者使用 'In' 扩展方法
    var users = db.Query<User>().Where(x => x.UserId.In(new[] {1,2,3,4})).ToList();

    在where子句中也可以使用许多字符串方法。这里有几个例子:

    var users = db.Query<User>().Where(x => x.Name.StartsWith("Bo")).ToList();
    var users = db.Query<User>().Where(x => x.Name.EndsWith("ob")).ToList();
    var users = db.Query<User>().Where(x => x.Name.Contains("o")).ToList();
    var users = db.Query<User>().Where(x => x.Name.ToLower() == "bob").ToList();
    var users = db.Query<User>().Where(x => x.Name.ToUpper() == "BOB").ToList();

    注意:并不是所有的操作都已经实现了。

    查询提供

    Query<T>

    查找用户id大于50的所有用户,按名称排序,只返回20个记录。

    var users = db.Query<User>()
       .Where(x => x.UserId > 50)
       .OrderBy(x => x.Name)
       .Limit(20, 40)
       .ToList();

    注意:

    查询将只在ToList()、ToEnumerable()或返回1值的标量方法中运行。

    UpdateMany<T>

    在必要的情况下,使用 Where 更新所有类型T 。

    var list = new[] {1, 2, 3, 4};
    
    // 只更新模板传递的(1、2、3、4)中 UserId 对象的 Name字段
    // 如果使用 ExecuteDefaults 方法,则不会设置默认属性 null,或为0的int
    db.UpdateMany<User>()
        .Where( x => x.UserId.In(list))
        //.ExcludeDefaults()
        .OnlyFields(x => x.Name)
        .Execute(new User() {Name = "test"});

    注意:

    查询只在执行调用时运行。

    DeleteMany<T>

    在必要的情况下,使用 Where 删除所有类型T 。

    var list = new[] {1, 2, 3, 4};
    
    db.DeleteMany<User>()
        .Where(x => list.Contains(x.UserId))
        .Execute();

    注意:

    查询只在执行调用时运行。

    版本列支持

    [VersionColumn]

    一个数字字段可以用来检测相互冲突的更新:

    [TableName("Users")]
    [PrimaryKey("UserId")]
    public class User
    {
        public int UserId { get;set; }
    
        [VersionColumn("VersionInt", VersionColumnType.Number)]
        public long VersionInt { get; set; }
    }

    更新将自动检查和增加版本,如果它已经过时,就会抛出 DBConcurrencyException 异常。

    这可以通过设置来禁用:VersionException = VersionExceptionHandling.Ignore。

     

    在SQL Server中,rowversion timestamp 数据类型

    可用于与VersionColumnType.RowVersion版本列:

    [TableName("Users")]
    [PrimaryKey("UserId")]
    public class User
    {
        public int UserId { get;set; }
    
        [VersionColumn("Version", VersionColumnType.RowVersion)]
        public byte[] Version { get; set; }
    }

    Sql模板

    您可以使用SqlBuilder在有条件的地方建立查询,例如,列,orderby等。

     var sqlBuilder = new SqlBuilder();
     var template = sqlBuilder.AddTemplate("select * from users where age > @0 and /**where**/", 10);

    这里你可以指定一个 Where、Select、Join、LeftJoin、OrderBy、OrderByCols、GroupBy 和 Having 相应的sql令牌在下面指定。

    /// Adds a filter. The Where keyword still needs to be specified. Uses /**where**/
    public SqlBuilder Where(string sql, params object[] parameters)
    
    /// Replaces the Select columns. Uses /**select**/
    public SqlBuilder Select(params string[] columns)
    
    /// Adds an Inner Join. Uses /**join**/
    public SqlBuilder Join(string sql, params object[] parameters)
    
    /// Adds a Left Join. Uses /**leftjoin**/
    public SqlBuilder LeftJoin(string sql, params object[] parameters)
    
    /// Adds an Order By clause. Uses /**orderby**/
    public SqlBuilder OrderBy(string sql, params object[] parameters)
    
    /// Adds columns in the Order By clause. Uses /**orderbycols**/
    public SqlBuilder OrderByCols(params string[] columns)
    
    /// Adds a Group By clause. Uses /**groupby**/
    public SqlBuilder GroupBy(string sql, params object[] parameters)
    
    /// Adds a Having clause. Uses /**having**/
    public SqlBuilder Having(string sql, params object[] parameters)

    语句可以被链接,并且每个新语句的参数从0开始。

    sqlBuilder
        .Where("height >= @0", 176)
        .Where("weight > @0 and weight < @1", 30, 60);
    
    var db = new Database("conn");
    db.Fetch<User>(template);

    可以在任何可以使用Sql类的地方使用模板。

  • 相关阅读:
    设计模式总结:单例模式(以及多线程、无序写入、volatile对单例的影响)
    android的WebView进度条
    三角形类内置成员函数(看看吧。。)
    VGA接口之显示彩色条
    Java I/O流操作(二)缓冲流
    oracle 单引号 双引号 连接符
    2013腾讯编程马拉松初赛(3月22)赛题及第2题代码(C++)
    Java I/O流操作(一)入门篇和System和Properties类介绍
    POJ 3264 Balanced Lineup
    成都行(二)
  • 原文地址:https://www.cnblogs.com/zyg316/p/10877139.html
Copyright © 2011-2022 走看看