I usually do just fine, but for some reason I cannot figure out why this particular query is defeating me.
For simplicity here is the database(Brand and PageTitle):
PageTitle is just a table to hold SEO data(there is only one row per Brand)
I want to : Select one row from PageTitle where brands = p (variable that holds the query string value)
This is an example of what I'm trying to do (If there are no records for the brand in PageTitle I don't want to throw an error).
var pages = da.PageTitles.Where(x => x.Brands.Single(z => z.BrandID == p)).SingleOrDefault();
if (pages.Any())
{
txtSeoTitle.Text = pages.Title;
txtSeoMetaKeywords.Text = pages.Keywords;
txtSeoMetaDesc.Text = pages.Description;
}
Unless i'm missing something obvious, can't you just do this:
var page = db.PageTitles
.FirstOrDefault(x => x.Brands.Any(y => y.BrandId == p));
SingleOrDefault will throw an exception if more than one row is returned, so i think you need FirstOrDefault.
Related
public ActionResult Index()
{
var results = db.Employee
.Where(d => d.JOBID == "Tester"
&& d.JOBID == "Developer"
&& d.Salary =="2000")
.ToList();
return View(results);
}
Results
NAME JOBID SALARY
John Tester 4000
joy Developer 2000
if you want to apply selection of two values from the same column you'd better use OR operator, This will list either Tester or Developer whom their salary is exactly 2000
public ActionResult Index()
{
var results = db.Employee
.Where(d =>
(d.JOBID == "Tester" || d.JOBID == "Developer") &&
d.Salary =="2000")
.ToList();
return View(results);
}
If you want to use the Where clause to select from one column based on multiple values, put the values you are looking for into a list first:
var jobIdList = new List<string>();
jobIdList.Add("Tester");
jobIdList.Add("Developer");
Now you can use the Contains clause to query any results that have a value in that list.
var results = db.Employee
.Where(d => (jobIdList.Contains(d.JOBID)
&& d.Salary =="2000"))
.ToList();
This way your query always works the same, but you can change the results you get by changing the values in jobIdList. Want to include Managers? jobIdList.Add("Manager");, then run your query again. Now you want to remove Developers and only get back Testers and Managers? jobIdList.Remove("Developer"), then run your query and get new results. This makes your query method much more flexible. Now you get back any employee where the JOBID is in the list AND the salary = 2000. (you might look at that salary value, hard coding that might not be ideal.)
I have a database with 2 tables: "Albumes" and "Categories".
Each Album has an "id" and a "categoryId" property. although each Category has a "name" property.
I can get the Album.id via QueryString from another page and show the desired Album details in a formview. now i want to show the name of category which contains that album.
I try to do this:
public string GetCategoryName(int albumCategoryId)
{
var _db = new Trying.Models.AlbumContext();
IQueryable<Category> query = _db.Categories;
query = query.Where(c => c.id == albumCategoryId);
Category ca = new Category();
//some code
return ca.name;
}
My problem is in "//some code" section! there, I must convert "IQueryabl query" to "Category ca".
How to do this?
Where returns a set of all matching entities but you only want a single one.
public string GetCategoryName(Int32 albumCategoryId)
{
using (var _db = new Trying.Models.AlbumContext())
{
return _db.Categories.Single(c.id == albumCategoryId).Name;
}
}
Using Single will throw an exception if there is no matching category and you should use this if you are sure that the category has to exist. If you are not sure whether the category exists or not, you can use SingleOrDefault to get null if there is no matching category. First or FirstOrDefault would work, too, but they are semantically wrong because you don't want the first category, you want to only one. SingleOrDefault obviously requires handling the case that there is no matching category.
public string GetCategoryName(Int32 albumCategoryId)
{
using (var _db = new Trying.Models.AlbumContext())
{
var category = _db.Categories.SingleOrDefault(c.id == albumCategoryId);
if (category != null)
{
return category.Name;
}
else
{
// Handle the no category found case by returning a default value,
// throwing an exception or what ever fits your needs.
}
}
}
Also note that you should use your database context in an usingstatement to ensure that it gets early and correctly disposed even in the case of an error.
Further you can access the name of the category directly by navigating through your navigation properties.
var categoryName = album.Category.Name;
This is obviously only useful when you have the album object available and you have to ensure that you load the category by either using lazy loading or explicitly including it if you use eager loading.
var album = _db.Albumes.Include(a => a.Category)
.Single(a => a.Id = 42);
This will load the album with Id 42 and because of Include(a => a.Category) also the category of this album. Whether this is better or worse than explicitly querying the category name depends of course on your requirements.
Try this:
public string GetCategoryName(int albumCategoryId)
{
var _db = new Trying.Models.AlbumContext();
IQueryable<Category> query = _db.Categories;
Category ca = query.First(c => c.id == albumCategoryId);
return ca.name;
}
I will explain with some examples, check the type of the variable because thats what each line is going to return:
list<Category> list = query.Where(c => c.id == albumCategoryId).AsEnumerable();
Category category= query.FisrtOrDefault(c => c.id == albumCategoryId);
IQueryable<T> is a collection.
You need to limit your collection to a single item.
query.Where will also result in a collection. I believe you're looking for a unique item by id. I would recommend Single instead:
var ca = query.Single(c => c.id == albumCategoryId);
return ca.name;
I am querying a SQL Server database from my ASP.net application in C#. Following is a part of my database schema.
I wrote following expression to get data from the database.
var query = db.DBMovies.Where(ent => ent.Id == Id).Join(db.DBCategories,
r => r.Id,
l => l.CategoryId,
(r, l) => new
{
Id = r.Id,
MovieName = r.Name,
Year = r.Year,
Category = r.Genre,
PosterURL = r.PosterURL,
});
foreach (var movie in query)
{
//something
}
In the part ent.Id == Id, the Id in the right refers to a parameter value. I referred this tutorial, but when I execute this, the execution does not get inside the foreach loop. I created a breakpoint inside the foreach loop and noticed that it didn't hit. Can somebody help me to find out the issue? And please suggest a way to quick watch the values returned by a lambda expression if possible.
Thank you.
Edit:
I changed the query as I have made a huge mistake first time, but I don't see any success even now.
var query = db.DBMovieToCategory.Where(ent => ent.CategoryId == Id).Join(db.DBMovies,
r => r.MovieId,
l => l.Id,
(r, l) => new
{
Id = l.Id,
MovieName = l.Name,
Year = l.Year,
Category = l.Genre,
PosterURL = l.PosterURL,
});
It looks like you're trying to join Movies to Categories by matching the Movie id to the Category id. Since the IDs are assigned independently, you will only get records back if by chance you have a Movie and a Category with the same ID.
Getting no records back would be why you never enter the foreach loop.
I see no relationships defined in your model, so DBMovies, DBCategories, and DBMoviesToCategories don't "know" they're related to each other.
What I have is a string of comma separated IDs that I'm receiving from a query string (e.g. 23,51,6,87,29). Alternately, that string could just say "all".
In my Linq query I need a way to say (in pseudo code):
from l in List<>
where l.Id = all_of_the_ids_in_csv
&& other conditions
select new {...}
I'm just not sure how to go about doing that. I'm not even sure what to google to get me going in the right direction. Any pointing in the right direction would be extremely helpful.
I would suggest to split your query in 2 - first part will select by ID, and the select one will select other conditions.
First of all: check if query string contains numbers, or is just all:
var IEnumerable<ListItemType> query = sourceList;
if(queryStringValue != "All")
{
var ids = queryStringValue.Split(new[] { ',' })
.Select(x => int.Parse(x)) // remove that line id item.Id is a string
.ToArray();
query = query.Where(item => ids.Contains(item.Id));
}
from l in query
// other conditions
select new {...}
Because LINQ queries have deffered execution you can build queries like that without performance drawback. Query won't be executed until you ask for results (by ToList call or enumeration).
If you really want it with just one LINQ query:
var idArray = all_of_the_ids_in_csv.Split(',');
from l in List<>
where (all_of_the_ids_in_csv == "All" || idArray.Contains(l.Id))
&& other conditions
select new {...}
The trick is using string.Split
var ids = string.split(rawIdString, ",").ToList();
var objects = ids.Where(id=> /*filter id here */).Select(id=>new { /* id will be the single id from the csv */ });
// at this point objects will be an IEnumerable<T> where T is whatever type you created in the new statement above
I am looking for a way to query for products in a catalog using filters on properties which have been assigned to the product based on the category to which the product belongs. So I have the following entities involved:
Products
-Id
-CategoryId
Categories
[Id, Name, UrlName]
Properties
[Id, CategoryId, Name, UrlName]
PropertyValues
[Id, PropertyId, Text, UrlText]
ProductPropertyValues
[ProductId, PropertyValueId]
When I add a product to the catalog, multiple ProductPropertyValues will be added based on the category and I would like to be able to filter all products from a category by selecting values for one or more properties. The business logic and SQL indexes and constraints make sure that all UrlNames and texts are unique for values properties and categories.
The solution will be a MVC3 EF code first based application and the routing is setup as followed:
/products/{categoryUrlName}/{*filters}
The filter routing part has a variable length so multiple filters can be applied. Each filter contains the UrlName of the property and the UrlText of the value separated by an underscore.
An url could look like this /products/websites/framework_mvc3/language_csharp
I will gather all filters, which I will hold in a list, by reading the URL. Now it is time to actually get the products based on multiple properties and I have been trying to find the right strategy.
Maybe there is another way to implement the filters. All larger web shops use category depending filters and I am still looking for the best way to implement the persistence part for this type of functionality. The suggested solutions result in an "or" resultset if multiple filters are selected. I can imagine that adding a text property to the product table in which all property values are stores as a joined string can work as well. I have no idea what this would cost performance wise. At leased there will be no complex join and the properties and their values will be received as text anyway.
Maybe the filtering mechanism can be done client side ass well.
The tricky part about this is sending the whole list into the database as a filter. Your approach of building up more and more where clauses can work:
productsInCategory = ProductRepository
.Where(p => p.Category.Name == category);
foreach (PropertyFilter pf in filterList)
{
PropertyFilter localVariableCopy = pf;
productsInCategory = from product in productsInCategory
where product.ProductProperties
.Any(pp => pp.PropertyValueId == localVariableCopy.ValueId)
select product;
}
Another way to go is to send the whole list in using the List.Contains method
List<int> valueIds = filterList.Select(pf => pf.ValueId).ToList();
productsInCategory = ProductRepository
.Where(p => p.Category.Name == category)
.Where(p => p.ProductProperties
.Any(pp => valueIds.Contains(pp.PropertyValueId)
);
IEnumerable<int> filters = filterList.Select(pf => pf.ValueId);
var products = from pp in ProductPropertyRepository
where filters.Contains(pp.PropertyValueId)
&& pp.Product.Category.Name == category
select pp.Product;
Bear in mind that as Contains is used, the filters will be passed in as sproc parameters, this means that you have to be careful not to exceed the sproc parameter limit.
I came up with a solution that even I can understand... by using the 'Contains' method you can chain as many WHERE's as you like. If the WHERE is an empty string, it's ignored (or evaluated as a select all). Here is my example of joining 2 tables in LINQ, applying multiple where clauses and populating a model class to be returned to the view.
public ActionResult Index()
{
string AssetGroupCode = "";
string StatusCode = "";
string SearchString = "";
var mdl = from a in _db.Assets
join t in _db.Tags on a.ASSETID equals t.ASSETID
where a.ASSETGROUPCODE.Contains(AssetGroupCode)
&& a.STATUSCODE.Contains(StatusCode)
&& (
a.PO.Contains(SearchString)
|| a.MODEL.Contains(SearchString)
|| a.USERNAME.Contains(SearchString)
|| a.LOCATION.Contains(SearchString)
|| t.TAGNUMBER.Contains(SearchString)
|| t.SERIALNUMBER.Contains(SearchString)
)
select new AssetListView
{
AssetId = a.ASSETID,
TagId = t.TAGID,
PO = a.PO,
Model = a.MODEL,
UserName = a.USERNAME,
Location = a.LOCATION,
Tag = t.TAGNUMBER,
SerialNum = t.SERIALNUMBER
};
return View(mdl);
}
I know this an old answer but if someone see's this I've built this project:
https://github.com/PoweredSoft/DynamicLinq
Which should be downloadable on nuget as well:
https://www.nuget.org/packages/PoweredSoft.DynamicLinq
You could use this to loop through your filter coming from query string and do
something in the lines of
query = query.Query(q =>
{
q.Compare("AuthorId", ConditionOperators.Equal, 1);
q.And(sq =>
{
sq.Compare("Content", ConditionOperators.Equal, "World");
sq.Or("Title", ConditionOperators.Contains, 3);
});
});