Dapper multi-mapping not returning null object when splitOn column is not in child object - dapper

I'm using dapper 1.50.2 with MySQL and running into a problem trying to map a left outer join child object to its parent. If I split on a column alias that doesn't actually exist in the child object, Dapper always creates a child object with default properties, even when there is nothing in the left join.
I created a simple example to demonstrate this:
public class ParentRecord
{
public string MemberID { get; set; }
public ChildRecord Child { get; set; }
}
public class ChildRecord
{
//public string Split { get; set; }
public string SomeField { get; set; }
}
using (MySqlConnection connection = new MySqlConnection(connectionString))
{
ParentRecord result = connection.Query<ParentRecord, ChildRecord, ParentRecord>(
#"SELECT 'FakeID' AS MemberID, NULL AS Split, NULL AS SomeField",
(mt, crt) =>
{
mt.Child = crt;
return mt;
},
splitOn: "Split").Single();
}
I would expect this to result a ParentRecord with the Child property set to null, but the Child property is set to a ChildRecord with all default fields.
If I uncomment the Split property in ChildRecord, or if I split on SomeField, this works as I'd expect.
Are there any good workarounds for this?
In the actual query I'm dealing with, there are multiple primary key and foreign key fields with the same names and I'd rather not change the property names in the POCOs to be unique. I'd prefer to be able to use column aliases that are just there to split on. I know this isn't normally how Dapper is set to up to work.
Any help would be appreciated, thanks.

This happen because the object Child initialize for default when you attribute the ctr param. Then the solution that I did implement was:
ParentRecord result = connection.Query<ParentRecord, ChildRecord, ParentRecord>(
#"SELECT 'FakeID' AS MemberID, NULL AS Split, NULL AS SomeField",
(mt, crt) =>
{
if (crt.SomeField != null){ mt.Child = crt; }
return mt;
},
splitOn: "Split").Single();

Related

map key value pair with entity properties in entity framework

Below is my code for entity and a function where I need to map entity TblEmployee from a key value pair.
In foreach loop I am getting values based on keys, what should be the best approach to do it?
public class TblEmployee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
}
public int Create()
{
tblEmployee employee = new tblEmployee();
using (var ctx = new theparkeee_testEntities())
{
foreach (string key in HttpContext.Current.Request.Form.AllKeys)
{
string value = HttpContext.Current.Request.Form[key];
//how to map value from key value pair to entity employee.
}
}
}
You can use System.Reflection to get the Properties of an object by their name with Type.GetProperty(string name). After you got the PropertyInfo, you can use SetValue to assign a value to it.
foreach (string key in HttpContext.Current.Request.Form.AllKeys) {
// note that "value" is a reserved word, do not use it as variable name
string val = HttpContext.Current.Request.Form[key];
var propertyInfo = typeof(TblEmployee).GetProperty(key); // can maybe be moved outside of the loop
if (propertyInfo != null) {
propertyInfo.SetValue(employee, val);
}
}
This will work for string properties. If the property is of another type, you have to find the correct type (again, using reflection) and cast the string value before assigning it.
Note that this is not the correct approach to store data in MVC. You should not work with the Request.Form directly, instead your POST action should accept a ViewModel that can be mapped (e.g. using Automapper) to the DB entity. I.e. let the ASP ModelBinder do its work, instead of reinventing the wheel!
[HttpPost]
public ActionResult Submit(MyViewModel postData) {
var employee = Mapper.Map<TblEmployee>(postData);
_ctx.Employees.Add(employee);
_ctx.SaveChanges();
return new HttpStatusCodeResult((int)HttpStatusCode.OK);
}

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.

wpf search in collection

How do I search into my collection ??
Can't get it working... Don't I just have to do :
Contacts c = new Contacts();
if (c.Contact_name == "Test") {
MessageBox.Show("exists!");
}
Does not work :-)
public ObservableCollection<Contacts> contacts = new ObservableCollection<Contacts>();
class Contacts
{
public string Contact_id { get; set; }
public string Contact_name { get; set; }
}
You're setting c to a new instance of Contacts which does not have the Contact_name property set to anything...
If you're trying to search a collection for a specific contact, the easiest way would probably be to use the following Linq statement, which will return the first object in the collecting matching your condition, or null if no object is found
contacts.FirstOrDefault(p => p.Contact_name == "Test");
There's other Linq extensions that may be better suited for you depending on what you want too, such as .Exists() if you only want to know if an item exists or not
If you're not using Linq, the easiest way would be with a loop
foreach(var c in contacts)
{
if (c.Contact_name == "Test") {
MessageBox.Show("exists!");
}
}

RIA services how do I return a single column?

I have a autocompletebox that is used to select a destination for a car booking program. For the itemssource of the autocomplete box I am trying to set it to all the previous destinations entered. The problem is that I can't work out how to return a single column 'Destination' of distinct destination values from my Booking class, e.g.
var query = from bk in ObjectContext.Bookings select new DestinationDTO { Destination = bk.Destination };
return query.Distinct();
. I have tried creating a shared DestinationDTO class to return just the single column but can't work out how to get this to inherit from Entity!!
Any ideas?
You need to have a property with a [Key] attribute in your DestinationDTO class. Then RIA services will be able to generate a corresponding class on the client side.
public class DestinationDTO
{
[Key]
public Guid Id { get; set; }
public string Destination { get; set; }
}
Then just do this:
var query = from bk in ObjectContext.Bookings
select new DestinationDTO { Destination = bk.Destination, Id = Guid.NewGuid() };
return query.Distinct();

HasMany: Empty list instead of null

I am using CastleProject ActiveRecord.
I have the following property in my class:
[HasMany(typeof(Order), Table = "Orders", ColumnKey = "OrderId")]
internal IList<Order> Orders
{
get;
set;
}
In case Orders table does not contain any orders, Orders property is null. Can I somehow point ActiveRecord that it should create empty list instead of returning null, without giving up autoproperty?
Not exactly what you want, but couldn't you instantiate an empty list in the constructor:
public MyClass()
{
Orders = new List<Order>();
}

Resources