how to map a dapper row with a .net object having a different (nested) structure - dapper

I'm looking for a way to map a row of the following table with the following object :
create table Foo (
Id BIGINT IDENTITY (1, 1) NOT NULL,
A int,
ACertainty float,
B string,
BCertainty float
....
)
public class FuzzyValue<T>{
public T Value { get; private set; }
public double Certainty { get; private set; }
}
class Foo {
public FuzzyValue<int> A { get; set;}
public FuzzyValue<string> B { get; set;}
...
}
Obviously, I can have dapper return a dynamic and do the mapping manually, but this manual tedious work kind of defeats the purpose of dapper, doesn't it?
Is there an easy way to have dapper do the mapping automatically?

I ended up writing a not so trivial mapper to do this.
If someone needs it, the source is here and there's a nuget package available here

Related

Set options values to an entity property

I come from Django, and with Django's ORM when defining a model I can set options, for example:
class MyModel(Model):
CHOICES = (...) # List of choices here
# it has tu be a 2-tuple list
# but that's is not the point right now.
choice = IntegerField(choices=CHOICES) # Set the choices.
Now, when MyModel is used to create an instance, the attribute(property) choice can hold only values defined in CHOICES.
There is some like this for EntityFrameworkCore-2.0?
It is something like this possible?
class MyEntity
{
[choices=EnumDefiningChoices]
property enum choices { get; set; }
}
A property can have a single defined value, an int, string, etc in order to be stored in a database.
An approach is to use 2 tables, one for your entity and one for the choices.
MyEntity:
public class MyEntity
{
public int Id { get; set; }
// all the other properties
public int ChoiceId { get; set; } // Here is the refference for the choice
public virtual Choice Choice { get; set; }
}
Choice:
public class Choice
{
public int Id { get; set; }
public string Name { get; set; }
}
As you can see the ChoiceId will allow only values from the Choice table.
However if you want to use an Enum there is no "blocking" mechanism using EF, this must be implemented at the application level.
Indeed, there is a way!
With EF > 6 you can do something like this:
public enum Option
{
option_1 = 1,
option_2,
option_3
}
class SomeEntity
{
public Option Option { get; set; }
}
And you can get the enum option name with:
var option_name = Option.GetName(typeof(Option), some_entity.option_2);
Console.WriteLine(option_name);
References
Working with Enumerated Values in Entity Framework
Enum.GetName Method (Type, Object)

Auto assign column value when row is created

I am using EF6 and SQL Server 2014.
I have something like the following simplified model:
public class Order
{
public int Id { get; set; }
public DateTime Created { get; set; }
public IEnumerable<OrderItem> OrderItems { get; set; }
}
public class OrderItem
{
public int Id { get; set; }
public int OrderId { get; set; }
public Order Order { get; set; }
public string ItemName { get; set; }
public int OrderItemNumber { get; set; }
}
The Id properties are standard auto-increment primary keys.
The OrderItem.OrderItemNumber property uniquely identifies an OrderItem within the context of a given Order.
When a new OrderItem row is inserted it needs to be assigned the next OrderItemNumber for the parent Order, something like
SELECT COALESCE(MAX(OrderItemNumber),0) FROM dbo.OrderItems WHERE OrderId = 2
Is there a means using EF6/SQL Server to auto-assign the OrderItemNumber at the point a row is inserted?
Although this proved an interesting learning experience on EF support for triggers (see https://github.com/NickStrupat/EntityFramework.Triggers) I eventually decided to re-model.
In this case my question was a result of incorrect modelling. The OrderItemNumber property was redundant so I removed it; the sequence the OrderItems were created can be inferred from the Id value, and there was no real requirement to allow re-sequencing.

Entity Framework Code First - One to Many relations from multiple tables

I have a BlobEntity table that contains paths to files for many other tables (tableX, tableY, tableZ, etc...) in my application.
The relation between all the other tables to BlobEntity table is one to many.
Example:
tableX -> BlobTable (OTM)
tableY -> BlobTable (OTM)
tableZ -> BlobTable (OTM)
and the relation is:
public virtual ICollection<BlobEntity> BlobEntity { get; set; }
I'm not sure if this is an issue, but entity framework Code First creates a new FK column in BlobEntity table for each source table.
In my case, BlobEntity contains three FK columns for tableX, tableY and tableZ.
In order to be efficiency, i rather create one column in BlobEntity that contains the FK for the source tables.
Is it reasonable?
Please advise...
Thanks.
No, you can't do this even in plain old SQL.
You can have a foreing key pointing to more than one table; that's why you need
three columns.
If you want to do a "trick" like this, you have to manually manage the relation (I mean, no real FK), but you can't map it into EF.
What about this?
public class EntityA
{
public int Id { get; set; }
public int MyFileID {get;set;}
public virtual MyFiles MyFile { get; set; }
}
public class EntityB
{
public int Id { get; set; }
public int MyFileID {get;set;}
public virtual MyFiles MyFile { get; set; }
}
public class MyFiles
{
public MyFiles()
{
// ReSharper disable once VirtualMemberCallInContructor
FilesForEntityA = new List<EntityA>();
// ReSharper disable once VirtualMemberCallInContructor
FilesForEntityB = new List<EntityB>();
}
public int Id { get; set; }
public int? EntityAId {get;set;}
public int? EntityBId {get;set;}
public virtual ICollection<EntityA> FilesForEntityA { get; set; }
public virtual ICollection<EntityB> FilesForEntityB { get; set; }
}
This way you can have the FK in place and you can easily manager multiple entities.
Obviously if you have many files for each entity, you can go with a N-to-N relationship, like this.

Value is not a convertible object

I have a simple query and Poco that I'm using with Dapper like so:
var jc = this.dbConnection.ExecuteScalar<JcUser>("SELECT loginid as Username,Password,coalesce(CustomerId,0) as CustomerId,TextProfileId,UxProfileId from \"user\" where id = #id", new {id = id});
Poco:
public class JcUser
{
public string UserName { get; set; }
public string Password { get; set; }
public int CustomerId{ get; set; }
public int TextProfileId { get; set; }
public int UxProfileId { get; set; }
}
When this executes it throws an exception with the message
Value is not a convertible object: System.String to JcUser
The stack trace ends up at: at System.Convert.ToType (System.Object value, System.Type conversionType, IFormatProvider provider, Boolean try_target_to_type)
Any ideas why its doing this?
Thanks
UPDATE: Using var jc = this.dbConnection.Query<JcUser>("SELECT loginid as Username,Password,coalesce(CustomerId,0) as CustomerId,TextProfileId,UxProfileId from \"user\" where id = #id", new {id = id}).First(); appears to work. I also realise I'm a moron and ExecuteScalar is only for one value. However, is my update the best way to retrieve only one row?
ExecuteScalar maps to the ADO.NET method of the same name. It returns at most one cell: one grid, one row, one column. As such, it is not intended for use with complex objects, and cannot work correctly in your case as you have multiple columns.
Dapper assumes you would only use that with simple types like int, string etc.
In your case, use:
var jc = this.dbConnection.Query<JcUser>(
sql, args).SingleOrDefault();
If you want to avoid a hidden List<> allocation you could also pass buffered: false.

Mapping fields in stored procedure to class properties with different names with Dapper

I have this exert from a POCO class with many fields:
public class Call
{
public int Id { get; set; }
public string Customer { get; set; }
public int StatusId { get; set; }
public int UserAssignedToId { get; set; }
public string UserAssignedToName { get; set; }
}
However my stored procedure returns different names to the properties above (in this case the Id is before:
IdCall
IdStatus
IdUserAssignedTo
This is the code I am using to execute the stored procedure:
var call = conn.Query<Call>("CallSPName", new { IdCall = callId }, commandType: CommandType.StoredProcedure).First();
How can I specify a mapping to say I would like "IdStatus" from my stored procedure map to "StatusId" in my POCO class and "IdCall" to "CallId" etc?
I don't have access to change the stored procedures as they are controlled by DBAs and older legacy systems are using them which would break if the fields got changed in the stored procedure.
Any ideas/thoughts appreciated.
The closest thing which comes to my mind is to have private properties mapped to columns returned by the stored procedure and make the public properties with the names you want setting and getting those private fields:
// ...
private int IdStatus;
public int StatusId {
get { return IdStatus; }
set { IdStatus = value; }
}
// ...

Resources