I am trying to return a result set that includes rows where any of three strings has a string match. My domain models look like this:
public class Customers
{
public int CustomerID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class BidNames
{
public int BidNameID { get; set; }
public int CustomerID { get; set; }
public string BidName { get; set; }
}
There is a FK between BidName.CustomerID and Customers.CustomerID and it is a one-to-many relationship where there can be multiple BidNames for a single Customer. When searching my customer table I want to bring back all records where there is a string match in FirstName, LastName or any of the associated BidNames. For this example I'll use a BidName search string of "ba".
from c in Customers
where c.FirstName.Contains("ba") || c.LastName.Contains("ba") || c.BidNames.Any(b=>BidNames.BidName.Contains("ba"))
orderby c.LastName, c.FirstName
select new { CustomerID = c.CustomerID, FirstName = c.FirstName, LastName = c.LastName }
It all works until I add the final criteria in the Where clause. I understand that c.BidNames is a collection and I'm looking to see if Any of them have a BidName that contains "ba". Where I'm running into trouble is trying to specify the BidNames.BidName column to search for the string. The code I've written above fails with "BidNames does not contain a definition for 'BidName'"
How do I write the last part of the Where clause so I can search all the BidNames.BidName fields associated with the Customer record? I hope and assume I can use the same syntax to specify the BidName field in the orderby and select clauses as well.
Many thanks,
BK
FINAL ANSWER:
from c in Customers
where
c.FirstName.Contains("ba") ||
c.LastName.Contains("ba") ||
c.BidNames.Any(b=>b.BidName.Contains("ba"))
orderby
c.LastName,
c.FirstName
select new {
CustomerID = c.CustomerID,
FirstName = c.FirstName,
LastName = c.LastName,
BidNames = c.BidNames.OrderBy(b=>b.BidName)
}
Try changing your where clause to
Where c.FirstName.Contains("ba") ||
c.LastName.Contains("ba") ||
c.BidNames.Any(b=>b.BidName.Contains("ba"))
In your Any clause, b is an instance of the BidNames class, so you want to access properties of that rather than the BidNames property of the Customer.
Related
I am facing a problem using Dapper.
I have two models:
public class ClientEventsModel
{
public int Id { get; set; }
public int ClientId { get; set; }
public ClientEventTypeLog EventType {get; set;}
public int Value { get; set; }
public DateTime Date { get; set; }
public string? Doer { get; set; }
}
[Serializable]
public class ExtentedClientEventsModel : ClientEventsModel
{
public List<string> Values { get; set; } = new List<string>();
}
One is inherited from the other.
And a request in the form:
var sqlStr = $#"SELECT ce.Id, ce.ClientId, ce.EventType, ce.Value, ce.Date, a.UserName AS Doer, cevn.`Values` FROM clients.client_events ce
LEFT JOIN `z-price`.aspnetusers a ON ce.Doer = a.Id_num
LEFT JOIN clients.clients_events_value_name cevn ON ce.Id = cevn.ClientEventsId
where ClientId = {clientId} and Date BETWEEN '{from.ToMysql()}' and '{to.AddDays(1).ToMysql()}'";
var result = DefaultConnection.Query<ExtentedClientEventsModel>(sqlStr);
When I execute the query in the client it returns 16 records. But when I use Dapper it returns 4 records. And only those with the Doer == null field.
I tried replacing the model with a dynamic type, but it didn't help.
Dapper doesn't get to invent the number of rows coming back. If Dapper says there were 4 rows, then one of two things:
you've found a niche edge case that hasn't been seen in the many years of Dapper
your query really does only return 4 rows
Now, I'm open to "1", but in reality "2" is much more likely. I suspect the real problem here is the parameters - or lack there-of. Never ever use concatenation to build SQL from values. Try instead:
const string sqlStr = #"
SELECT ce.Id, ce.ClientId, ce.EventType, ce.Value, ce.Date, a.UserName AS Doer, cevn.`Values` FROM clients.client_events ce
LEFT JOIN `z-price`.aspnetusers a ON ce.Doer = a.Id_num
LEFT JOIN clients.clients_events_value_name cevn ON ce.Id = cevn.ClientEventsId
where ClientId = #clientId and Date BETWEEN #from and #to";
var result = DefaultConnection.Query<ExtentedClientEventsModel>(
sqlStr, new { clientId, from, to = to.AddDays(1) }).AsList();
(note: different databases have different syntax for parameters; if #clientId etc doesn't work, try :clientId, $clientId, etc)
This is what the request gives in the DbForge client
And this is what Dapper returns:
at that
I am new in Asp.net
now i want to try to start a social network project
I have 3 tables
User
Userid
-Username
-Email
-Password
-Name
-Profilepic
Post
-Postid -Content -Postdate -Userid
Friendlist
Friendlistid - userid - friendid -status
i want to load the post that from my friend and myself
This is my sql code
select b.userid, a.Friendid, c.name, b.postid, b.Content, b.postdate, c.profilepic
from friendlist a
left join [user] c on a.friendid = c.userid
left join post b on a.friendid = b.userid
where a.userid = 1 AND a.Status = 1 OR a.Userid = 1
ORDER BY postid desc
The problem that i faced was my post will repeat
For example, my friendlist table has 3 friends, my every single post will repeat 3 times and my friend post stay normal.
Any solution for this sql code?
If you have a relationship between the tables and are using Entity Framework. You can simply invoke the tables below its "friendlist". You can take this query return creating a class specific to this return
public class ListFriendsGroup
{
public int UserId { get; set; }
public int friendId { get; set; }
public int PostId{ get; set; }
public string Name { get; set; }
public string Content { get; set; }
public DataTime PostData { get; set; }
public string ProfilePic { get; set; }
}
var friendlist = Context.friendList.Include("user").Include("post")
// HERE .GroupBy(...
.Select(f => new ListFriendsGroup() { Userid = f.post.userid, FriendId = f.Friendid, Name = f.user.name, PostId = f.post.postid, Content = f.post.Content, PostData = f.post.postdate, Profilepic = f.user.profilepic }).ToList()
Read about the Group By clause to perform grouping of data
Group by, Count and Lambda Expression
I have the following object:
public class VehicleMake
{
[Column(Name = "MakeID")]
public int Id { get; set; }
public string Name { get; set; }
}
To get a list of vehicle makes, I am doing the following:
var vehicleMakes = _db.Fetch<VehicleMake>(#"SELECT DISTINCT(m.MakeID) AS Id, m.Name
FROM vehicles v
INNER JOIN makes m on m.MakeID = v.Make
WHERE [Year] = #year
ORDER BY m.Name", new { year });
When I run the SQL in SSMS, it returns the correct data, but in VS, it is mapping 0 for every Id property.
Ah, I got it, in case anyone else runs into the problem. Since I am doing:
SELECT DISTINCT(m.MakeID) as Id..., there is no reason to have:
[Column(Name = "MakeID")] since I am aliasing the column as Id already.
Assume that I have a very simple db diagram:
and a view for it:
create view vTraining
as
select t.Id as TrainingId,t.[Status] ,
t.[User], t.Title,t.Organisation,t.[Month],t.[Year],
s.Id as SubjectId, s.Name as SubjectName,
c.Text as Comment
from Training t
join Subject s on s.Training = t.Id
join Comment c on c.Training = t.Id
with sample data:
As you can see, this is a single training with three subjects.
I want to map this result to this structure by linq to sql:
public class ViewModel
{
public string Comment { set; get; }
public List<Item> Trainings { set; get; }
}
public class Item
{
public int TrainingId { set; get; }
public int User { set; get; }
public int Status { set; get; }
public string Title { set; get; }
public string Organisation { set; get; }
public int? Month { set; get; }
public int Year { set; get; }
public List<KeyValuePair<int, string>> Subjects { set; get; }
}
This is my query, that I created:
var data = (from training in dc.vTrainings
group training by new
{
training.TrainingId,
training.Status,
training.Month,
training.Organisation,
training.Title
}
into g
select new ViewModel()
{
Comment = g.Select(x =>
x.Comment).First(),
Trainings = g.Select(
x => new Item()
{
Month = x.Month,
Organisation = x.Organisation,
Title = x.Title,
Year = x.Year,
Subjects = g.Select(
z => new KeyValuePair<int, string>(z.SubjectId, z.SubjectName)).ToList()
}).ToList()
})//.GroupBy(x => x.Trainings).Select(x => x.Key)
.ToList();
Unfortunatelly the result I get is not the one I want:
The ViewModel object is created only ones what is ok, but for each single subject, the new Item is created (should be one). The Subjets list is created correctly. I tried to create a second group by, and some other things, but this is the best result I can get for now.
How to write this query to get one ViewModel object which has one Item object with three subjects?
I finally got my the proper result:
var data = (from g in
(from training in dc.vTrainings
where training.Status ==1
group training
by new
{
training.TrainingId,
training.Status,
training.Month,
training.Organisation,
training.Title
}
into g
select g).AsEnumerable()
select new ViewModel()
{
Comment = g.Select(x =>
x.Comment).FirstOrDefault(),
Trainings = g.GroupBy(x => x.Status).Select(
x => new Item()
{
Month = g.Key.Month,
Organisation = g.Key.Organisation,
Title = g.Key.Title,
Subjects = (from i in g select new KeyValuePair<int, string>(i.SubjectId, i.SubjectName)).ToList()
}).ToList()
}).ToList();
This query works only for one training, but for me this is not a problem, because I filtering it by the newest status. Still I'm curious how to write it for more than one training.
Try this:
var trainings =
dc.vTrainings
.GroupBy(
t => new
{
t.TrainingId,
t.Status,
t.Month,
t.Organisation,
t.Title,
t.User,
t.Year
},
t =>
new
{
t.SubjectId,
t.SubjectName
})
.ToList()
.Select(
t =>
new Item
{
TrainingId = t.Key.TrainingId,
Status = t.Key.Status,
Month = t.Key.Month,
Organisation = t.Key.Organisation,
Title = t.Key.Title,
User = t.Key.User,
Year = t.Key.Year,
Subjects =
t.Select(s => new KeyValuePair<int,string>(s.SubjectId,s.SubjectName)).ToList()
});
If I want to execute a query that is based on joins between multiple tables, then how would this be coded in a code-first approach using Entity Framework 4.1? For example, I want to execute the following query:
SELECT p.ProductId
, p.Name AS ProductName
, c.Name AS CategoryName
FROM
Products p
INNER JOIN Categories c
ON c.CategoryId = p.CategoryId
You will create classes like:
public class Product {
public int ProductId { get; set; }
public string Name { get; set; }
public int CategoryId { get; set; }
public virtual Category Category { get; set; }
}
public class Category {
public int CategoryId { get; set; }
public string Name { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
And you will use this query where join will be created automatically from navigation properties:
var query = from p in context.Products
select new {
ProductId = p.ProductId,
ProductName = p.Name,
CategoryName = p.Category.Name
};