henkmollema / dapper-fluentmap Goto Github PK
View Code? Open in Web Editor NEWProvides a simple API to fluently map POCO properties to database columns when using Dapper.
License: MIT License
Provides a simple API to fluently map POCO properties to database columns when using Dapper.
License: MIT License
This is the first time I'm trying to use dapper-fluentmap v2 and I would like to have the set protected in my model classes but now it is not possible.
I noticed that inherited properties are not mapped by fluent mapper. Debugging led me to line 45 in the file "src\Dapper.FluentMap\TypeMaps\FluentConventionTypeMap.cs"
Changing
.Where(map => map.PropertyInfo.DeclaringType == type &&
to
.Where(map => map.PropertyInfo.ReflectedType == type &&
fixes the problem
I couldn't find a way.
Thanks
Using a class that looks something like:
[DataContract] public class Note
{
[DataMember] public DateTime Date { get; set; }
}
}
And mapped:
public class NoteMap : EntityMap<Note>
{
public NoteMap()
{
Map(n => n.Date).ToColumn("LINE_DT");
}
}
Causes an ArgumentNullException
exception to be thrown when the db row is deserialised. Renaming the field to PDate fixes this.
First of all a quick thank you for all the work you've put into this project.
Currently i'm trying to combine conventions and an entitymap to map a poco to one of my db tables.
The convention covers most of the database column names, however most of our primary keys have the same name. This obviously causes issues when working with joins.
Is it possible to let my convention handle the mapping for certain columns and using an entitymap to handle the other columns my convention can't?
So far i haven't been able to make it work, it seems to either take one or the other.
On .net 4.5.2 (Dapper 1.50.2), Dapper.FluentMap 1.5.0 and 1.5.1 using the PropertyTransformConvention from the readme applied via:
FluentMapper.Initialize(config =>
{
config.AddConvention<PropertyTransformConvention>()
.ForEntitiesInCurrentAssembly("App.Domain.Models")
}
in conjunction with Dapper multi mapping throws an exception:
Finding mappings for column 'id' yielded more than 1 PropertyMap. The conventions should be more specific.
Works perfectly with 1.4.1 and below.
For example these models:
public class Product
{
public int Id { get; set; }
}
public class Order
{
public int Id { get; set; }
}
With this convention:
public class PrefixConvention : Convention
{
public PrefixConvention()
{
Properties<int>()
.Where(p => p.Name.ToLower() == "id")
.Configure(config => config.HasColumnName("autID");
}
}
Causes an exception which tells you that duplicate mappings are found for the column autID
since it finds the PropertyMap
instance for Order
and Product
. A check for the property type should be added to the filter predicate.
Hi,
I have a type B that inherits from type A, and a Property P defined in A.
When I try to map that property in type B, an exception is thrown at the DommelColumnNameResolver, that the key is not present in the entity maps dictionary.
I suggest that instead of using the DeclaringType for the lookup, use the ReflectedType.
Maybe this issue exists in other places too, I haven't checked.
The entire explanation can be found here:
http://stackoverflow.com/questions/40881195/mapping-value-objects-with-dapper
I'm trying to map a value object to my domain model. This nested VO isn't a table is just a VO in my rich domain. Simplified scenario when I get the error at application startup:
public class Cliente
{
public Guid Id { get; set; }
public CPF CPF { get; set; }
}
public class CPF
{
public string Numero { get; set; }
}
public class DapperMappings
{
public static void RegisterDapperMappings()
{
FluentMapper.Initialize(config =>
{
config.AddMap(new ClienteMap());
});
}
}
public class ClienteMap : EntityMap<Cliente>
{
public ClienteMap()
{
Map(c => c.CPF.Numero).ToColumn("CPF");
}
}
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
DapperMappings.RegisterDapperMappings();
}
}
I always receive the same error at application initialization:
Index was outside the bounds of the array.
Exception Details: System.IndexOutOfRangeException: Index was outside the bounds of the array.
Using ASP.NET MVC 5, more details about the Stack Trace can be found at StackOverflow link
Trying to query a table with a field of bit(1)
to a POCO property that is bool
by manual mapping (i.e EntityMap<T>
). How do you do that?
Taken from the main Dapper Readme:
var sql =
@"
select * from Customers where CustomerId = @id
select * from Orders where CustomerId = @id
select * from Returns where CustomerId = @id";
using (var multi = connection.QueryMultiple(sql, new {id=selectedId}))
{
var customer = multi.Read<Customer>().Single();
var orders = multi.Read<Order>().ToList();
var returns = multi.Read<Return>().ToList();
...
}
If you have conventions defined (e.g. the regex example on the FluentMap Readme), the columns don't get mapped in any of the resulting POCOs.
Currently, when no entity mapping is found for a type, an exception is thrown. When a resolver implementation returns null
or string.Empty
, the default resolver should be used.
Resolver
class methods to use the default implementation as fallbackHello,
Excuse the noob question here. I'm not sure it's the proper place to ask this but I could not find any answer
I'm beginner in this kind of stuff so I don't really understand the goal of FluentMap.
At the moment, I'm using Dapper, and Dapper.fastCRUD inside a WPF MVVM application. I can do all CRUD stuff and it's really easy and nice.
I'm not sure I understand what FluentMap would add to my application.
Does mapping my Model object with Mapping class such as UserMap : EntityMap will provide a way to automatically update my DB when my User properties change?
So I would not have to code myself the SqlConn.Update(....) with Dapper.FastCrud ...?
I'm executing UpdateAsync()
on a really basic object having also added a map that ignores 3 columns, but I'm still getting the invalid column name
error. FluentMapper.Initialize
was called beforehand and I see the mapping when calling Dapper's SqlMapper.GetTypeMap()
. Any ideas?
Considering these models:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public Category Category { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
}
And the following EntityMap
configuration:
public class ProductMap : EntityMap<Product>
{
public ProductMap()
{
Map(p => p.Id).ToColumn("ProductId", false);
Map(p => p.Name).ToColumn("ProductName", false);
Map(p => p.Category.Id).ToColumn("CategoryId", false);
Map(p => p.Category.Name).ToColumn("CategoryName", false);
}
}
Is there a way to map result of a SQL query with such a structure to my model?
SELECT ProductId, ProductName, CategoryId, CategoryName
FROM dbo.Product;
Currently I'm getting an exception that a duplicate mapping for Id
column has been declared:
System.Exception
HResult=0x80131500
Message=Duplicate mapping detected. Property 'Id' is already mapped to column 'Id'.
Source=Dapper.FluentMap
StackTrace:
at Dapper.FluentMap.Mapping.EntityMapBase`2.ThrowIfDuplicateMapping(IPropertyMap map)
at Dapper.FluentMap.Mapping.EntityMapBase`2.Map(Expression`1 expression)
at IDAR.Domain.Tests.ProductMap..ctor() in C:\Users\buina\source\repos\Learning\Learning.Domain.Tests\Dummy.cs:line 45
at IDAR.Domain.Tests.Dummy.NestedProperty() in C:\Users\buina\source\repos\Learning\Learning.Domain.Tests\Dummy.cs:line 13
In the Transformations example... if the database column is lower case, like "hello_world", and the POCO is HelloWorld, the property is never populated.
However if the database column is "Hello_World" then it works.
Is this to be expected? If so, what is the solution to be able to map a POCO property HelloWorld to hello_world column?
Port the application to DNX.
Create implementations for the IKeyPropertyResolver
, ITableNameResolver
and IColumnNameResolver
interfaces of Dommel using the configured mappings.
Tasks:
DommelKeyPropertyResolver
DommelTableNameResolver
DommelColumnNameResolver
i try to create mapper like
public class WordsMap : EntityMap<Words>
{
}
the class Words have a property which is a list object,
i found I cannot mapper it ,and maybe i need use where(p=>p.perpertyName).tocolumn("alias")
?
Dapper.FluentMap throws the following exception:
Method 'FindExplicitConstructor' in type 'Dapper.FluentMap.TypeMaps.FluentMapTypeMap`1' from assembly 'Dapper.FluentMap, Version=1.3.2.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.
when configuring a manual mapping:
FluentMapper.Intialize(config =>
{
config.AddMap(new MnemonicTranslationMap());
});
using the following mapping strategy:
public class MnemonicTranslationMap : EntityMap<MnemonicTranslation>
{
public MnemonicTranslationMap()
{
Map(x => x.CreatedAt)
.ToColumn("CreatedAt");
Map(x => x.CreatedBy)
.ToColumn("CreatedBy");
Map(x => x.UpdatedAt)
.ToColumn("UpdatedAt");
Map(x => x.UpdatedBy)
.ToColumn("UpdatedBy");
}
}
lib/net35
and lib/net40
Port the application to .NET Standard 2.0
For some reason mapping of byte arrays seem to be ignore when inserting new records.
Hello
I am experiencing difficulty using the library within a strong named assembly for it not being signed. I had the same issue with Dapper but with the new version of Dapper.Strongname I overcame it. But the FluentMap library does not seem to provide a version that works with the strong named Dapper. Would it be possible to get one in place?
Thanks and Regards
Shubha
public class InventoryMovementTypeMap : DommelEntityMap<InventoryMovementType>
{
public InventoryMovementTypeMap()
{
ToTable("inventory_movement_types");
Map(i => InventoryMovementTypeId).ToColumn("InventoryMovementTypeID").IsKey().IsIdentity();
Map(i => i.Action).ToColumn("Action", caseSensitive: false);
Map(i => i.Code).ToColumn("Code", caseSensitive: false);
Map(i => i.Name).ToColumn("Name", caseSensitive: false);
}
}
public class RegisterMappings
{
public static void Register()
{
FluentMapper.Initialize(config =>
{
config.AddMap(new InventoryMovementTypeMap());
config.ForDommel();
});
}
}
It's correct??
The Dommel extension of Dapper.FluentMap needs an implementation of the IPropertyResolver
interface, which should take Ignore
into account.
Should be Initialize
.
It would be very good if we had the possibility to perform a mapping of 1 -> N
Initially, It could be could only follow first-level mapping.
For example
public class Profile
{
public int Id { get; set; }
public string Name { get; set; }
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public IEnumerable<Profile> Type { get; set; }
}`
When using Dapper QueryMultiple, it appears the mapped columns are not working.
In my case QueryMultiple returns 3 tables.
var ds = con.QueryMultiple("uspSELNodes", p, commandType: CommandType.StoredProcedure);
var rows = ds.Read().ToDictionary(v => v.RowNo); //Returns a dynamic dictionary
var total = ds.Read<int>().First(); //Returns table 2 that contains just an int for a total
var columns = ds.Read<DynamicTable.Column>(); // Does not seem to map properly.
Class is as below :
public class Column : IDynamicTableColumn
{
public string Prefix { get; set; }
public string Name { get; set; }
public string DisplayName { get; set; }
public int Order { get; set; }
public bool Orderable { get; set; }
public bool Filterable { get; set; }
public int Width { get; set; }
public string ResourceName { get; set; }
}
Mapping :
private class DynamicColumnMap : EntityMap<DynamicTable.Column>
{
public DynamicColumnMap()
{
Map(x => x.Prefix).ToColumn("column_prefix");
Map(x => x.Name).ToColumn("column_name");
Map(x => x.Order).ToColumn("display_order");
Map(x => x.Orderable).ToColumn("can_be_ordered");
Map(x => x.Filterable).ToColumn("can_be_filtered");
Map(x => x.Width).ToColumn("column_width_in_pixels");
}
}
Config :
FluentMapper.Initialize(config =>
{
config.AddMap(new DynamicColumnMap());
config.AddConvention<LowerCaseConvention> ().ForEntitiesInAssembly(typeof(Configuration).Assembly);
});
The columns that match name for name for example DisplayName all get their correct values from Dapper, the mapped columns appear to be getting the defaults for their type, strings empty, bools false and ints 0.
Am I initializing this correctly?
How would you (or is there currently a way) to do a case insensitive match using the "ToColumn" method when creating a map?
ie. I have something like:
Map(p => p.ServiceDate).ToColumn("svc_date");
But the table column is actually SVC_DATE... Is there a way to ignore the case during that match? Thanks in advance for any assistance and thank you for putting this project up.
I need to specify that the ID is generated by a sequence in Oracle I would need something like the example below. It's possible?
Map(x => x.Id).IsKey().IsSequence("SEQUENCE_NAME").ToColumn("ID_ERCA");
v2 of Dapper.FluentMap will bring several new features and bugfixes while maintaining a simple API.
ReflectedType
and DeclaringType
ReflectedType
is inconsistent and is not available on .NET Standard 1.3. Providing different implementations according to the target framework seems like a bad idea. The best way to solve this is to not use ReflectedType
at all and get a hold on a reference to the object.
Related issues:
Dommel does not use all available mappings provided by Dapper.FluentMap. Make use of the extensibility points of Dommel and use the mapping configuration of Dapper.FluentMap.
Related issues:
Any more suggestions are welcome! ๐
Accessing an entity map for a type which has not entity map results in a KeyNotFound
exception due to the fact that an indexer is used without a ContainsKey
check:
var mapping = FluentMapper.EntityMaps[type] as IDommelEntityMap;
TryGetValue
should be used here.
When a PropertyMap
is added for an EntityMap
, the mapping should be checked for multiple mappings on the same property.
The app should have unit tests to test mappings etc.
Dapper 1.50.5, Dapper.FluentMap 2.0.0-beta1.
using Dapper;
using Dapper.FluentMap;
using Dapper.FluentMap.Mapping;
using Npgsql;
using NpgsqlTypes;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
namespace NullableDecimalError
{
class Program
{
static void Main(string[] args)
{
FluentMapper.Initialize(config =>
{
config.AddMap(new EntityDtoMap());
});
var connection = new NpgsqlConnection("connectionstring");
var procedureName = "test.get_numeric";
var cursorName = "p_out_cursor";
var p = new PostgreDynamicParameters();
p.Add(cursorName, cursorName, NpgsqlDbType.Refcursor, ParameterDirection.InputOutput);
using (connection)
{
connection.Open();
var transaction = connection.BeginTransaction();
connection.Execute(procedureName, param: p, commandType: CommandType.StoredProcedure);
var sql = "fetch all in " + cursorName;
//expection here
var result = connection.Query<EntityDto>(sql, null, commandType: CommandType.Text).ToList();
transaction.Commit();
}
}
}
public class EntityDto
{
public decimal? Value { get; set; }
}
public class EntityDtoMap : EntityMappingBuilder<EntityDto>
{
public EntityDtoMap()
{
EntityMapping.IsCaseSensitive = false;
Map(p => p.Value).ToColumn("operation_id");
}
}
public class PostgreDynamicParameters : SqlMapper.IDynamicParameters
{
private readonly List<NpgsqlParameter> postgreParameters = new List<NpgsqlParameter>();
public void Add(string name, object value, NpgsqlDbType dbType, ParameterDirection direction)
{
var p = new NpgsqlParameter();
p.ParameterName = "@" + name;
p.NpgsqlDbType = dbType;
p.Direction = direction;
if (value == null)
{
p.Value = DBNull.Value;
}
else
{
p.Value = value;
}
postgreParameters.Add(p);
}
public void AddParameters(IDbCommand command, SqlMapper.Identity identity)
{
var postgreCommand = command as NpgsqlCommand;
if (postgreCommand != null)
{
postgreCommand.Parameters.AddRange(postgreParameters.ToArray());
}
}
}
}
DB:
create table test.test_numeric (
value numeric
);
insert into test.test_numeric(value)
values(123.45);
CREATE OR REPLACE FUNCTION test.get_numeric(
inout p_out_cursor refcursor
)
RETURNS refcursor AS
$body$
declare
v_value numeric;
BEGIN
open p_out_cursor for
select value as operation_id
from test_nsi.test_numeric;
END;
$body$
LANGUAGE 'plpgsql';
This code throws ArgumentNullException
at Query
line. If Value
is declared decimal
it works just fine.
Stack:
at System.Reflection.Emit.DynamicILGenerator.Emit(OpCode opcode, MethodInfo meth)
at Dapper.SqlMapper.GetTypeDeserializerImpl(Type type, IDataReader reader, Int32 startBound, Int32 length, Boolean returnNullIfFirstMissing)
at Dapper.SqlMapper.TypeDeserializerCache.GetReader(IDataReader reader, Int32 startBound, Int32 length, Boolean returnNullIfFirstMissing)
at Dapper.SqlMapper.TypeDeserializerCache.GetReader(Type type, IDataReader reader, Int32 startBound, Int32 length, Boolean returnNullIfFirstMissing)
at Dapper.SqlMapper.GetTypeDeserializer(Type type, IDataReader reader, Int32 startBound, Int32 length, Boolean returnNullIfFirstMissing)
at Dapper.SqlMapper.GetDeserializer(Type type, IDataReader reader, Int32 startBound, Int32 length, Boolean returnNullIfFirstMissing)
at Dapper.SqlMapper.<QueryImpl>d__136`1.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
Hello Henk,
And thanks for the amazing job, i'm using your libraries now on my current project.
I was wondering if you planned to support multiple keys in your mapper ?
Regards
When creating a convention, one should be able to configure a property name transformation. Example using regex:
public class PropertyNameTransformConvention : Convention
{
public PropertyNameTransformConvention()
{
// Converts camel case properties to uppercase with underscores. (FirstName -> FIRST_NAME)
Properties()
.Configure(c => c.Transform(input => Regex.Replace(input: input, pattern: "([A-Z])([A-Z][a-z])|([a-z0-9])([A-Z])", replacement: "$1$3_$2$4")));
}
}
There should also be some built-in transformations.
Here's my model:
public class HouseAccount
{
public string ServiceCenter { get; set; }
public string ServiceUnit { get; set; }
public string AccountNumber { get; set; }
public string AccountName { get; set; }
}
Here's my map:
public class HouseAccountMap : EntityMap<HouseAccount>
{
public void ProductMap()
{
Map(a => a.ServiceCenter)
.ToColumn("parent_region_id");
Map(a => a.ServiceUnit)
.ToColumn("region_id");
Map(a => a.AccountNumber)
.ToColumn("cust_id");
Map(a => a.AccountName)
.ToColumn("bo_name");
}
}
Here's my sql
SELECT s.parent_region_id, s.region_id, c.cust_id, n.bo_name
FROM table
Using OWIN I have a startup.cs and I'm calling FluentMapper.Initialize() in there, like this:
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<Repository>().AsImplementedInterfaces();
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
WebApiConfig.Register(config);
app.UseWebApi(config);
config
.EnableSwagger(c => c.SingleApiVersion("v1", "House Accounts API! Welcome!"))
.EnableSwaggerUi();
// Map Dapper Query to POCO
FluentMapper.Initialize(mapConfig =>
{
mapConfig.AddMap(new HouseAccountMap());
});
}
My model gets serialized as all null values.
Can you please create a strong name version of this package? So it can be easily used with Dapper.StrongName package.
Thank you!
Hi there. I tried to map with conventions fields which are returns by stored procedure. It was not successful. Please pay attention to this problem.
class Program
{
static void Main(string[] args)
{
FluentMapper.Initialize(config =>
{
// Configure all entities in the current assembly with an optional namespaces filter.
config.AddConvention<ColumnMappingConvention>()
.ForEntitiesInCurrentAssembly();
});
using (SqlConnection cnn = new SqlConnection(connectionString))
{
var result = cnn.Query<HorseDiscrepancyDTO>("dbo.DiscrepancyTodayByHorseGet", new { horse_Id = 111111, Date = DateTimeOffset.UtcNow.AddDays(-1) }, commandType: CommandType.StoredProcedure).ToArray();
}
}
}
public class ColumnMappingConvention : Convention
{
public ColumnMappingConvention()
{
Properties()
.Configure(x => x.Transform(s => Regex.Replace(input: s, pattern: "Race_Name", replacement: "Race Name")));
Properties()
.Configure(x => x.Transform(s => s.Replace("1", "/")));
}
}
public class HorseDiscrepancyDTO
{
public DateTimeOffset? Race_Date1Time { get; set; }
public string Race_Name { get; set; }
In the DB the fields Race_Date1Time and Race_Name have original names "Race date/time" and "Race Name". Thank you.
A user should be able to define conventions which apply on a single property of a POCO.
For instance:
class TestPoco
{
public string HelloWorld { get; set; }
}
Where HelloWorld
should map to either "hello_world"
or "HelloWorld"
.
Possible solutions:
Just a quick thank-you from Entities.Sqlite. We utilized a few of your ideas and used some modified source from your project. Your project license will be included as required.
When I mark a property with .Ignore() in the map, dommel doesn't handle this in the insert method, and there is an exception.
It should have a condition in the Linq expression that excludes ignored properties.
Love this mapping for dapper, but I need a version that will work with dotnet core 2. Please enter as an enhancement.
The 'namespaces' parameter on the ForEntitiesInCurrentAssembly
is required, otherwise the conventions don't work.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.