Dapper .Net : table column and model property type mismatch - dapper

Actually I have a query which returns result containing column(for ex.Address) of type varchar but the domain model for that table containing property of type object(for ex. Address Address).Because of which it trows error which says could not cast string to Comment.I cant figure out how to resolve this issue with dapper .net.
Code snippet:
IEnumerable<Account> resultList = conn.Query<Account>(#"
SELECT *
FROM Account
WHERE shopId = #ShopId",
new { ShopId = shopId });
The Account object is for example.
public class Account {
public int? Id {get;set;}
public string Name {get;set;}
public Address Address {get;set;}
public string Country {get;set;}
public int ShopId {get; set;}
}
As there is type mismatch between database table column(Address) and domain model property(Address) dapper throws exception.So is there is any way to map that properties though dapper..

Another option is to use Dapper's Multi-Mapping feature.
public class TheAccount
{
public int? Id { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
public string Country { get; set; }
public int ShopId { get; set; }
}
public class Address
{
public string Street { get; set; }
public string City { get; set; }
}
public class Class1
{
[Test]
public void MultiMappingTest()
{
var conn =
new SqlConnection(
#"Data Source=.\SQLEXPRESS; Integrated Security=true; Initial Catalog=MyDb");
conn.Open();
const string sql = "select Id = 1, Name = 'John Doe', Country = 'USA', ShopId = 99, " +
" Street = '123 Elm Street', City = 'Gotham'";
var result = conn.Query<TheAccount, Address, TheAccount>(sql,
(account, address) =>
{
account.Address = address;
return account;
}, splitOn: "Street").First();
Assert.That(result.Address.Street, Is.Not.Null);
Assert.That(result.Country, Is.Not.Null);
Assert.That(result.Name, Is.Not.Null);
}
}
The only issue I see with this is that you'll have to list all of the Account fields, followed by the Address fields in your select statement, to allow splitOn to work.

Since there is a type mismatch between your POCO and your database, you'll need to provide a mapping between the two.
public class Account {
public int? Id {get;set;}
public string Name {get;set;}
public string DBAddress {get;set;}
public Address Address
{
// Propbably optimize here to only create it once.
get { return new Address(this.DBAddress); }
}
public string Country {get;set;}
public int ShopId {get; set;}
}
Something like that - you match the db column to the property DBAddress (You need to provide an alias like SELECT Address as DBAddress instead of *) and provide a get method on your Address object which creates / reuses a type of Address with the contents of the db value.

Related

Pass parameters to report Devexpress

Please tell me. Created 2 classes (Data Model)
public class User
{
public int UserID { get; set; }
public string UserName { get; set; }
public string Department { get; set; }
public int Office { get; set; }
public string Position { get; set; }
public string Phone { get; set; }
public float Mobile { get; set; }
public string EMail { get; set; }
public string Login { get; set; }
public int idArm { get; set; }
}
and
public class arm
{
public int id { get; set; }
public string name { get; set; }
public string Detalis { get; set; }
}
I installed 2 GridControlls on the form
And through DataSet showed data
string connectionString = ConfigurationManager.ConnectionStrings["connectionSIPiT"].ConnectionString;
string command = "SELECT * FROM Users";
string command2 = "SELECT * FROM arm";
sqlConnection = new SqlConnection(connectionString);
SqlDataAdapter adapter = new SqlDataAdapter(command2, sqlConnection);
SqlDataAdapter adapter1 = new SqlDataAdapter(command, sqlConnection);
DataSet dataset1 = new DataSet();
adapter.Fill(dataset1, "arm");
adapter1.Fill(dataset1, "Users");
DataColumn keyColumn = dataset1.Tables[0].Columns[0];
DataColumn foreignKeyColumn = dataset1.Tables[1].Columns[9];
dataset1.Relations.Add("armUsers", keyColumn, foreignKeyColumn);
armBindingSource.DataSource = dataset1;
armBindingSource.DataMember = "arm";
userBindingSource.DataSource = armBindingSource;
userBindingSource.DataMember = "armUsers";
gridControl1.DataSource = userBindingSource;
gridControl2.DataSource = armBindingSource;
How do I select a row in the main table GridControll. Send report data. Or pass the id of the main table to build the report? Can anyone come across such a task?
Make sure that the Modifiers property for the report parameter is set to Public or Internal
Use the GridView.GetRowCellValue method to get the ID column value of the focused record
The following assumes that you have a report called MyReport and it has a parameter called MyParameter.
var id = Convert.ToInt32(gridView1.GetRowCellValue(gridView1.FocusedRowHandle, gridView1.Columns["UserID"]));
var rpt = new MyNewReport();
rpt.MyParameter.Value = id; //Make sure the MyParameter's Modifiers property is set to Public or Internal.

Null data returned using a 1:1 model

I have two SQL tables, User and UserType joined with UserType as a foreign key, with their respective models in ASP. To my understanding, this should be a 1:1 relationship (correct me if I'm wrong). One unique user, set as a type of user (being admin, super admin, user etc).
When I try and retrieve a list of users, it returns a null on the property UserType.
I used Google to get this far, but I'm struggling to get this particular issue fixed.
At one point I got an error stating: "Unable to determine the principal end of an association". To get around that, I included a Required annotation (didn't work) and a ForeignKey annotation (didn't work either) in both models, both simultaneously and separately.
This is what I have so far.
[Table("Users", Schema = "dbo")]
public class Users
{
[Key, ForeignKey("UserType")]
public Guid Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string ContactNumber { get; set; }
public UserType UserType { get; set; }
public string IsActive { get; set; }
}
[Table("UserType", Schema = "dbo")]
public class UserType
{
[Key]
public Guid Id { get; set; }
public string Type { get; set; }
public string Description { get; set; }
public string IsActive { get; set; }
public Users Users { get; set; }
}
I'm using the below LINQ method to retrieve the data:
public PagedTables<Users> GetAllUsers(Pagination pagination)
{
using (var db = new DbContext())
{
var user = new PagedTables<Users>()
{
Data = db.Users.OrderBy(U => U.Id).Skip(pagination.Page).Take(pagination.Limit).ToList(),
Count = db.Users.Count()
};
return user;
}
}
A break point on the users var shows that the property UserType returns null. I would expect the assigned user type to be joined onto the user.
Any help would be appreciated. Thanks
My EF background is database-first but if you are eager loading (i.e. not lazy loading) then are you missing an Include to tell LINQ to go and get the UserType? Something like;
Data = db.Users.OrderBy(U => U.Id).Skip(pagination.Page).Take(pagination.Limit).Include(U => U.UserType).ToList(),

How to Increase the performance of Entityframework ExecuteSqlCommand() with different ObjectContexts?

We are Using Service fabric Actor application,in that we have multiple actors. if i want to Update 10 records each record acts as like different individual instance.so when we insert it will create new ObjectContext everytime. so we con't store cache data in context level. so my datamodel is like
public class StudentData {
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public String StudentId { set; get; }
public string StudentName {get;set;}
public String StudentAge { set; get; }
public string StudentDob {get;set;}
public String StudentSTD { set; get; }
public string StudentEmail {get;set;}
public String StudentAddress { set; get; }
public string StudentReligion {get;set;}
}
And when we want to update 10 students 10 object instances will create. so for every instance it will call the below method. so below method will call 10 times as different instance id.
public async Update(){
using(var context = new DatabaseContext()){
context.InfoObjectDatas.Attach(studentObj);
context.Entry(studentObj).State = System.Data.Entity.EntityState.Modified;
await context.SaveChangesAsync();
} }
We are Using Service fabric Actor application,in that we have multiple actors. if i want to insert 10 records each record acts as like different individual instance.so when we insert it will create new ObjectContext everytime. so we con't store cache data in context level. so my datamodel is like
public class StudentData {
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public String StudentId { set; get; }
public string StudentName {get;set;}
public String StudentAge { set; get; }
public string StudentDob {get;set;}
public String StudentSTD { set; get; }
public string StudentEmail {get;set;}
public String StudentAddress { set; get; }
public string StudentReligion {get;set;}
}
And when we want to insert 10 students 10 object instances will create. so for every instance it will call . so i am using like for loop for 10 objects.
public async insert(){
using(var context = new DatabaseContext()){
Student st=new Student();
context.StudentData.Add(st);
context.StudentData.SaveChanges();
} }

Execute complex raw SQL query in EF6

I am developing a web api using Entity Framework 6. I have to execute a complex SQL query which is getting data from multiple tables as shown in the code. I have tried but get the following error:
The data reader has more than one field. Multiple fields are not valid
for EDM primitive or enumeration types.
The query successfully return data in SSMS Query Analyzer.
[HttpGet]
public IHttpActionResult getJobNo(string cmpCode, string branchCode)
{
string query = string.Format(
#"select
M.S1, M.S2, C.S2 As S30, M.S3, SC.S2 As S31, M.D1, M.S5,
JT.S2 As S32, M.S6, TM.S2 As S33, M.S10
from
MERTRM M, CMF C, CMFS SC, PMCD JT, PMCD TM
where
M.S100 = 'JOB' and M.S102 = '{0}' and
M.S108 = '{1}' and
M.S101 not in('U', 'C', 'F') and
M.S2 = C.S1 and C.S102 = '{0}' and
C.S100 = 'CC' and M.S3 = SC.S1 and SC.S102 = '{0}' and
C.S1 = SC.S109 and M.S5 = JT.S1 and JT.S102 = '{0}' and
JT.S100 = 'JTP' and M.S6 = TM.S1 and TM.S102 = '{0}' and
TM.S100 = 'TPM'",
cmpCode,branchCode);
var result = db.Database.SqlQuery<string>(query);
return Json(result.ToArray());
}
Since the query returns a list of records so when I tried as follows:
var result = db.Database.SqlQuery<IEnumerable<string>>(query).ToList();
It gave me the following error:
'System.Collections.Generic.IEnumerable`1[System.String]' may not be
abstract and must include a default constructor.
How can I execute this query?
Regards!
you must use a DAO/DTO type:
class MyDAOType {
public String S1 {get; set;}
public String S2 {get; set;}
//...
public String S10 {get; set;}
}
and the query
var result = db.Database.SqlQuery<MyDAOType>(query);
Probably the easiest way is to define your own class that has the same fields as returned SQL and use this class as output.
public class MyReport {
public string S1 { get; set; }
public string S2 { get; set; }
public string S30 { get; set; }
public string S3 { get; set; }
public string S2 { get; set; }
public string S31 { get; set; }
public string D1 { get; set; }
public string S5 { get; set; }
public string S32 { get; set; }
public string S6 { get; set; }
public string S33 { get; set; }
public string S10 { get; set; }
}
var result = db.Database.SqlQuery<MyReport>(query).ToList();

JSON.NET Array Serialization in C#.NET

I am trying to create a class for serializing and deserializing arrays. The class I have created, appears to be working for deserializing, but when I try to serialize the array, I am having issues. I am a fairly new C# developer and I am sure I have left an important piece out of my code, I just am not sure what.
Below is a copy of the class I created:
namespace PinnacleCartFormAPI
{
class clsGetCustomersResponse
{
public Customer Customer = new Customer();//{ get; set; }
}
public class Customer
{
public Int32 UserId;
public string UserName;
public CustBilling Billing = new CustBilling();
public AddressBook[] AddressBook;// AddressBook = new AddressBook();
}
public class CustBilling
{
public string FullName, FirstName, LastName, Email, Company, Phone;
public CustAddress Address = new CustAddress();
}
public class CustAddress
{
public string Name, Street1, Street2, City, State, Zip, Country;
}
public class AddressBook
{
public string Name, Street1, Street2, City, State, Zip, Country;
}
}
As you can see, the AddressBook class needs to be an Array. I believe my issue is related to the fact that I am not initiating the AddressBook class properly as an array.
Below, is a copy of the calling code that adds values to the different elements of the class:
clsGetCustomersResponse GetCustomersResp = new clsGetCustomersResponse();
GetCustomersResp.Customer.UserId = 123456;
GetCustomersResp.Customer.UserName = "Username";
GetCustomersResp.Customer.Billing.FullName = "Full Name";
GetCustomersResp.Customer.Billing.FirstName = "First Name";
GetCustomersResp.Customer.Billing.LastName = "Last Name";
GetCustomersResp.Customer.Billing.Email = "email#domain.com";
GetCustomersResp.Customer.Billing.Phone = "7778889999";
GetCustomersResp.Customer.Billing.Address.Name = "Address Name";
GetCustomersResp.Customer.Billing.Address.Street1 = "Address Street 1";
GetCustomersResp.Customer.Billing.Address.Street2 = "";
GetCustomersResp.Customer.Billing.Address.City = "Address City";
GetCustomersResp.Customer.Billing.Address.State = "Address State";
GetCustomersResp.Customer.Billing.Address.Zip = "Address Zip";
GetCustomersResp.Customer.Billing.Address.Country = "Address Country";
GetCustomersResp.Customer.AddressBook[0].Name = "Address Name";
GetCustomersResp.Customer.AddressBook[0].Street1 = "Address Street 1";
GetCustomersResp.Customer.AddressBook[0].Street2 = "";
GetCustomersResp.Customer.AddressBook[0].City = "Address City";
GetCustomersResp.Customer.AddressBook[0].State = "Address State";
GetCustomersResp.Customer.AddressBook[0].Zip = "Address Zip";
GetCustomersResp.Customer.AddressBook[0].Country = "Address Country";
As soon as I hit the bolded lines, I receive the following error:
"Object reference not set to an instance of an object"
Again, I believe this is a result of me not properly initializing the AddressBook portion of the code. However, I am not certain how to do that with the array.
Can you please provide me with some direction on this?
Thanks,
Zach
(Just to be clear, this doesn't really have anything to do with JSON.)
Yes, you have to initialize an array before you start putting values in it. Unfortunately arrays are of a fixed size - you can't change the size (e.g. by adding an element) after they've been created. I would suggest using a List<AddressBook> instead of an array. Then you can use:
// This initialization could be in the type itself
GetCustomersResp.Customer.AddressBook = new List<AddressBook>();
AddressBook address = new AddressBook();
address.Name = "Address Name";
address.Street1 = "Address Street 1";
// etc
GetCustomersResp.Customer.AddressBook.Add(address);
I'd also be tempted to rename the AddressBook type - it's just a single address, not a whole address book. The property within Customer could still be called AddressBook, as an address book is a collection of addresses.
Try this (for 10 address books):
GetCustomersResp.Customer.AddressBook = new AddressBook[10];
You need to instantiate your array before you try to assign elements in it
Agreed with Jon's answer - I didn't spend a ton of time on it, but maybe you'll find this refactored set of classes useful:
namespace Pinnacle.Cart.Customers
{
public class RetrieveResponse
{
public RetrieveResponse() { }
public RetrieveResponse(Customer customer) {
Customer = customer;
}
public Customer Customer { get; set; }
}
public class Customer
{
public Customer() {
Billing = new BillingInfo();
AddressBook = new List<AddressBookEntry>();
}
public Int UserId { get; set; }
public String UserName { get; set; }
public BillingInfo Billing { get; set; }
public List<AddressBookEntry> AddressBook { get; set; }
public class BillingInfo
{
public BillingInfo() { Address = new Address(); }
public String FullName { get; set; }
public String FirstName { get; set; }
public String LastName { get; set; }
public String Email { get; set; }
public String Company { get; set; }
public String Phone { get; set; }
public Address Address { get; set; }
}
}
public class Address
{
public String Street1 { get; set; }
public String Street2 { get; set; }
public String City { get; set; }
public String State { get; set; }
public String Zip { get; set; }
public String Country { get; set; }
}
public class AddressBookEntry : Address
{
public string Name { get; set; }
}
}

Resources