Using Dapper with multiple inner joins - c#

I am trying to use Dapper with the following sql string but I am unable to get it work:
string groupsStringDetailed = "SELECT SUSERGROUP.NAME, SUSERGROUP.DESCRIPTION, SPROGRAMS.PROGRAMNAME, SOBJECTS.NAME FROM ((SIDE.SADMIT SADMIT " +
"INNER JOIN SIDE.SOBJECTS SOBJECTS ON (SADMIT.PROGRAMID=SOBJECTS.PROGRAMID) AND (SADMIT.OBJECTID=SOBJECTS.ID)) " +
"INNER JOIN SIDE.SUSERGROUP SUSERGROUP ON SADMIT.GROUPID=SUSERGROUP.GROUPID) " +
"INNER JOIN SIDE.SPROGRAMS SPROGRAMS ON SOBJECTS.PROGRAMID=SPROGRAMS.ID " +
"WHERE SUSERGROUP.NAME NOT LIKE '%REPORT' ORDER BY SUSERGROUP.NAME, SPROGRAMS.PROGRAMNAME";
I have the following model classes:
public class SAdmit
{
public int GROUPID { get; set; }
public int OBJECTID { get; set; }
public int PROGRAMID { get; set; }
}
public class SObjects
{
public int ID { get; set; }
public int PROGRAMID { get; set; }
public string NAME { get; set; }
}
public class SPrograms
{
public int ID { get; set; }
public string PROGRAMNAME { get; set; }
}
public class SUserGroup
{
public int GROUPID { get; set; }
public string NAME { get; set; }
public string DESCRIPTION { get; set; }
public int VWLISTDEPTH { get; set; }
public int WDNBDAYHISTORY { get; set; }
public string RPDIRECTORY { get; set; }
public string SENDEREMAIL { get; set; }
public int CONNECTION_TIMEOUT { get; set; }
public int APPROVALSTATUS { get; set; }
}
I createad a custom group class hoping to map easier those models:
public class CustomSGroup
{
public SUserGroup Group { get; set; }
public SPrograms Programs { get; set; }
public SObjects Objects { get; set; }
}
I am trying to use Dapper to get results I want like this:
var output = await cnn.QueryAsync<CustomSGroup, SAdmit, SObjects, SPrograms, CustomSGroup>(groupsStringDetailed, (g, a, o, p) =>
{
a.PROGRAMID = o.PROGRAMID;
a.OBJECTID = o.ID;
a.GROUPID = g.Group.GROUPID;
o.PROGRAMID = p.ID;
return g;
}, splitOn: "PROGRAMID, OBJECTID, GROUPID, NAME");
but I am unable to see the big picture and what I am doing wrong because it throws an exception
"When using the multi-mapping APIs ensure you set the splitOn param if you have keys other than Id\r\nParameter name: splitOn"
I am able to use Dapper with a simpler (one) inner join sql string, but this one I cannot get it work.

I reviewed the code and I've come to the conclusion that you simply are not including the fields you need to split on. Add the following fields to your query (perhaps adding distinct labels for the types that share similar field names.
PROGRAMID, OBJECTID, GROUPID, NAME

Related

Dapper easiest and fastest way to map single columns to multiple classes?

I have a class that looks like this
public Guid assessmentId { get; set; }
public string? applicationNumber { get; set; }
public ApplicationStatus? applicationStatus { get; set; }
public List<CompanyInformationModel>? companyInformationModel { get; set; }
public List<LocationInformationModel>? locationInformationModels { get; set; }
public List<JobInformationModel>? jobInformationModel { get; set; }
public class CompanyInformationModel
{
public Guid CompanyInformationId { get; set; }
public string? companyName { get; set; }
public string? contactName { get; set; }
public string? primaryPhone { get; set; }
public string? secondaryPhone { get; set; }
public string? email { get; set; }
public string? hourlyRate { get; set; }
}
public class LocationInformationModel
{
public Guid LocationInformationId { get; set; }
public string? address1 { get; set; }
public string? address2 { get; set; }
public string? city { get; set; }
public string? state { get; set; }
public string? zip { get; set; }
}
public class JobInformationModel
{
Guid JobInformationId { get; set; }
string? jobTitle { get; set; }
string? jobDescription { get; set; }
}
public enum ApplicationStatus
{
[Description("Pending")]
Pending,
[Description("Approved")]
Approved,
[Description("Declined")]
Declined
}
I query my table with joins like so in dapper
var sqlStatement = $#"Select * from SituationalAssessment s
join CompanyInformation c on c.CompanyInformationId = s.AssessmentId
join LocationInformation l on l.LocationInformationId = s.AssessmentId
join JobInformation j on j.JobInformationId = s.AssessmentId";
var retVal= await _dapperHelper.ExecuteQueryAsync<AssessmentModel>(sqlStatement);
My results will look like this
AssessmentId ApplicationNumber ApplicationStatus DateCreated ModifiedDateCreated CompanyInformationId CompanyName ContactName PrimaryPhone SecondaryPhone Email HourlyRate LocationInformationId Address1 Address2 City State Zip JobInformationId JobTitle JobDescription
78FE1852-5A26-4624-925C-74653DE9DAD9 227114 Pending 2023-02-08 13:57:52.743 NULL 78FE1852-5A26-4624-925C-74653DE9DAD9 Company Test Test Contact 123-234-2343 NULL test1#email.com NULL 78FE1852-5A26-4624-925C-74653DE9DAD9 123 Main Ste Apt 201 Los Angeles CA 90210 78FE1852-5A26-4624-925C-74653DE9DAD9 TEst Test Description
How do I map the results of CompanyInformation, LocationInformation and JobInformation to their own classes automatically in dapper?
The columns in the database are the exact same names as the fields in my classes
I assume that assessmentId, CompanyInformationId, LocationInformationId, and JobInformationId are the primary keys of the related tables. If it is so then your relationships between these tables should be 1 to 1 not 1 to many. And your assessment model should look like this :
public class AssesmentModel {
public Guid assessmentId { get; set; }
public string? applicationNumber { get; set; }
public ApplicationStatus? applicationStatus { get; set; }
public CompanyInformationModel? companyInformationModel { get; set; }
public LocationInformationModel? locationInformationModel { get; set; }
public JobInformationModel? jobInformationModel { get; set; }
}
Once we fix that then we can use the dappers splitOn parameter to split the query between the models.
var assessments = await connection.QueryAsync<AssesmentModel, CompanyInformationModel, LocationInformationModel, JobInformationModel>(sqlStatement, (assesment, company, location, job) => {
assesment.companyInformationModel = company;
assesment.locationInformationModel = location;
assesment.jobInformationModel = job;
return assesment;
}, splitOn: "CompanyInformationId, LocationInformationId, JobInformationId");
Need to mention that using explicit column names (instead of just *) in your query would be nice since dapper uses string.Split like operation to split the columns, changes to the related tables might break the query later on.
Edit
If you have somehow 1 to many relationships between those same method can be applied in this scenario like this :
var assessments = await connection.QueryAsync<AssesmentModel, CompanyInformationModel, LocationInformationModel, JobInformationModel>(sqlStatement, (assesment, company, location, job) => {
assesment.companyInformationModels.Add(company);
assesment.locationInformationModels.Add(location);
assesment.jobInformationModels.Add(job);
return assesment;
}, splitOn: "CompanyInformationId, LocationInformationId, JobInformationId");

SQL Query to Linq Query Result into complex object

I have SQL Query ready, and that I want its result into a complex SQL object. I want to use Linq to achieve the result.
public class VMPackageList
{
public string PackageName { get; set; }
public string ShortTitle { get; set; }
}
public class VMPackageItenary
{
public string PackageName { get; set; }
public string Day { get; set; }
public string Title { get; set; }
public string Detail { get; set; }
}
public class VMPackageHighlight
{
public string PackageName { get; set; }
public string Highlightname { get; set; }
public string HighlightDesc { get; set; }
}
The expected result in below class
public class VMPackageDetails
{
public VMPackageList vmPackage { get; set; }
public VMPackageItenary[] vmPackageItenary { get; set; }
public VMPackageHighlight[] vmPackageHighlights { get; set; }
}
Below are the SQL query and its result, the same way I want to get into
SQL table data query
This is my result query
I had tried with below code to achieve but I did not get success
var packages = packageRepository.Table;
var highlights = packageHighlightRepository.Table;
var itenaries = packageItenaryRepository.Table;
var data = (from package in packages
join highlight in highlights on package.PackageName equals highlight.PackageName
join iteratory in itenaries on package.PackageName equals iteratory.PackageName //&&
where package.PackageName == packageName //&& highlight.PackageName equals iteratory.PackageName
select new VMPackageDetails
{
// vmPackage = package
}).ToList();
Can anyone help me to get the result?

Listview/Datagrid binding from query generated list

So I have a query that returns values from multiple tables with a left join.
But I can't seem to get the data from left join table.
public IEnumerable<TipsTricks> GetTipsTricks()
{
using(var connection = new SqlConnection(Connection.Instance.ConnectionString))
{
return connection.Query<TipsTricks>(#"SELECT tt.ID, cat.Omschrijving, tt.Info, tt.Onderwerp, tt.Firma FROM tblTipsAndTricks as tt
LEFT JOIN tblTT_Categorieen as cat on cat.Id = tt.CategorieID ");
}
}
I then do in code behind to bind it to Datagrid.ItemsSource:
public void initialize()
{
List<TipsTricks> tipstricks = DatabaseManager.Instance.TipsTricksRepository.GetTipsTricks().ToList();
DgTipsTricks.ItemsSource = tipstricks;
}
Class TipsTricks
public class TipsTricks
{
public int Id { get; set; }
public string Info { get; set; }
public string Onderwerp { get; set; }
public string Firma { get; set; }
string Omschrijving { get; set; }
}
Also tried the binding in de XAML without succes.
So I would like a column in the datagrid showing the content of cat.Omschrijving from the left join table tblTT_Categorieen.
Thanks!
Try making the property string Omschrijvin "public"
as shown below
public class TipsTricks
{
public int Id { get; set; }
public string Info { get; set; }
public string Onderwerp { get; set; }
public string Firma { get; set; }
public string Omschrijving { get; set; }
}

c#. EF entity sql. How to get entity with related objects?

I have made simple model for example.
public class Publisher
{
public int Id { get; set; }
public string Title { get; set; }
public Address Location { get; set; }
public virtual ICollection<Book> Books { get; set; }
}
public class Address
{
public string Country { get; set; }
public string City { get; set; }
public string Street { get; set; }
public string HouseNumber { get; set; }
}
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public int LanguageId { get; set; }
public int? PublisherId { get; set; }
}
I need to get publishers with related books. I know how to do it using linq to entities. Is it possible to solve a problem using entity sql?
public class CatalogContext : DbContext {...}
public List<Publisher> GetByCity(string city)
{
var result = new List<Publisher>();
string queryString;
queryString = String.Format(#"SELECT VALUE row(a,b)
FROM CatalogContext.Publishers AS a
join CatalogContext.Books AS b on a.Id = b.PublisherId
WHERE a.Location.City = '{0}'", city);
var rows = ((IObjectContextAdapter)_context).ObjectContext.CreateQuery<DbDataRecord>(queryString).ToList();
return ???
}
Query returns required data but it's List<DbDataRecord> - list of pairs <publisher, book>. How to translate it to list of publishers with filled navigation property "Books"?
Is it possible to write query which directly returns List<Publisher>?
you can do the following:
var result = ObjectContext.Publishers.Include("Books").Include("Locations")
.Where(c => c.Location.City = "SOME_CITY").Select(c => c);
Include - basically joins the table.
Then you can drill down to books by doing the following:
var test = result[0].Books;
Why are you using direct sql command instead of Entity Framework code style?

EF4.1 - Attribute Evaluating to null at runtime

I'm using EF4.1 code first to create a simple database app with SQL CE 4 backend. I have a Product class and a CallItem class defined as so:
class CallItem
{
public int id { get; set; }
public float discount { get; set; }
public virtual Product Product { get; set; }
}
class Product
{
public int id { get; set; }
public decimal BaseCost { get; set; }
public int UnitSize { get; set; }
public bool isWasteOil { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Ingredients { get; set; }
}
edit - When I am creating a collection of CallItems using a LINQ query, I cannot access the attributes of the Product attached to each CallItem, eg
var callItems = from ci in context.CallItems select ci;
foreach(CallItem callItem in callItems)
{
RunSheet nrs = new RunSheet();
nrs.prodCode = callitem.Product.Code;
}
Interrogating the database shows that Productid in CallItems is being populated. However, the following line generates a NullReferenceException during run time:
nrs.prodCode = callitem.Product.Code;
Because callitem.Product is evaluating to null. Is this something to do with lazy loading and if so how can I resolve the issue?
RunSheet is another class, nrs is an instance whose attribute 'prodCode' I want to populate with the CallItem's Product's code.
Thanks!
From that code what you've showed it should work. Have you tried explicit loading?
var callItems = from ci in context.CallItems.Include(c => c.Product) select ci;
foreach(CallItem callItem in callItems)
{
RunSheet nrs = new RunSheet();
nrs.prodCode = callitem.Product.Code;
}
public class CallItem
{
public int Id { get; set; }
public float Discount { get; set; }
public virtual Product Product { get; set; }
}
public class Product
{
public int Id { get; set; }
public decimal BaseCost { get; set; }
public int UnitSize { get; set; }
public bool IsWasteOil { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Ingredients { get; set; }
}
using (var context = new StackOverFlowContext())
{
var p = new Product
{
Id = 1,
BaseCost = 200,
Code = "Hola",
Description = "Soe description",
Ingredients = "Some ingredients",
IsWasteOil = true,
Name = "My Product",
UnitSize = 10
};
var item = new CallItem
{
Id = 101,
Discount = 10,
Product = p
};
context.CallItems.Add(item);
context.SaveChanges();
var result = from temp in context.CallItems
select temp;
Console.WriteLine("CallItem Id"+result.First().Id);
Console.WriteLine("ProductId"+result.First().Product.Id);
}
I wrote the above code with the following output
CallItemId 1
ProductId 1
The sql Profiler showed this
SELECT TOP (1)
[c].[Id] AS [Id],
[c].[Discount] AS [Discount],
[c].[Product_Id] AS [Product_Id]
FROM [dbo].[CallItems] AS [c]
It was too long for a comment ,so i put it here .

Categories

Resources