I have a table in my database called Profile, I have another table called ProfileConfirmed. The purpose of this table is to confirm that the person confirmed his email address. I would like to have it that when I loop through all the profiles, the profiles that have not been confirmed do not show up.
Here is my foreach
#foreach (var c in Model.Profiles)
{
}
Here is where I am getting the profiles in my models
public List<Cleaner> GetProfiles()
{
using (var context = new CleanerDataContext(_connectionString))
{
var loadOptions = new DataLoadOptions();
loadOptions.LoadWith<Cleaner>(c => c.ProfileConfirmed);
context.LoadOptions = loadOptions;
return context.Cleaners.ToList();
}
}
I suggest you disregard the 2nd table and add an 'IsConfirmed' with a bit data type column on your 1st table. Then
var query = (from profiles in context.ProfileTable
where IsConfirmed == true select profiles).ToList();
return query;
Less code. Less hassle.
The problem is with this part:
return context.Cleaners.ToList();
ToList() method will always get a new copy of the array, though the objects in it aren't copies, they are the same references as in the original array.
public List<Cleaner> GetProfiles()
{
using (var context = new CleanerDataContext(_connectionString))
{
var loadOptions = new DataLoadOptions();
loadOptions.LoadWith<Cleaner>(c => c.ProfileConfirmed);
context.LoadOptions = loadOptions;
var confirmedProfilers =
from cust in db.SomeTable
where c.ProfileConfirmed == true
select cust;
return confirmedProfilers.ToList();
}
}
Related
I am kind of new to Lambda Expressions, I have tried to work out a simple solution to the following task I have set myself.
A customer has a collection of cars. Use LINQ to get a total number of cars he has.
Code below, not sure if this is correct? My second question is how do you display the TotalNumberCars to a textbox?
using (Entities dbcontext = new Entities())
{
var ListByOwner = from c in dbcontext.Owners
where c.OwnerID == OwnerID
group c by c.Cars into g
select new
{
Owner = g.Key,
TotalNumberCars = g.Sum(x => x.Cars)
};
lblTotalCars.Text = ListByOwner.ToList();
}
I don't know how your entity data model is structured, but I would do it like this:
using (var dbContext = new Entities())
{
var numberOfCars = dbContext.Cars.Count(c => c.OwnerId == OwnderId);
lblTotalCars.Text = numberOfCars.ToString();
}
If there's no c.OwnerId then maybe you can access it by typing c.Owner.OwnerId.
ListByOwner.ToList() is an array (generic list) of your new items from your Select projection. Each item is a dynamic entity with two properties of Owner and TotalNumberCars. You need to index or foreach into the list, extract what is needed into a string and that can be your text.
Such as lblTotalCars.Text = ListByOwner[0].Owner; will display the first item's owner.
Take this and fill in what you need.
check this code
lblTotalCars.Text = ListByOwner.ToList().sum(c=>c.TotalNumberCars).ToString();
I've got a table Installation which can contains one or many Equipements.
And for functionnal reasons, I've overwritten my table Installation and added a field NbrEquipements.
I want to fill this field with Linq, but I'm stuck...
Due to special reasons, there is no relation between these to tables. So, no Installation.Equipements member into my class. Therefore, no Installation.Equipements.Count...
I'm trying some stuff. Here is my code:
var query = RepoInstallation.AsQueryable();
// Some filter
query = query.Where(i => i.City.RegionId == pRegionId));
int?[] etatIds = { 2, 3 };
query = (from i in query
select new Installation
{
NbrEquipements= (from e in RepoEquipement.AsQueryable()
where e.InstallationSpecialId == i.SpecialId
&& (etatIds.Contains(e.EquEtat))
select e.SasId
).Count()
});
But with this try, I got this error:
The entity or complex type 'myModel.Installation' cannot be constructed in a LINQ to Entities query
I've tried some other stuff but I'm always turning around...
Another thing that can be useful for me: It would be great to fill a field called Equipements which is a List<Equipement>.
After that, I would be able to Count this list...
Is it possible ?
Tell me if I'm not clear.
Thanks in advance.
Here is the final code:
//In the class:
[Dependency]
public MyEntities MyEntities { get; set; }
//My Methode code:
var query = MyEntities .SasInstallations.AsQueryable();
// Some filter
query = query.Where(i => i.City.RegionId == pRegionId));
var liste = new List<Installation>();
var queryWithListEquipements =
from i in query
select new
{
Ins = i,
EquipementsTemp = (from eq in MyEntities.Equipements.AsQueryable()
where eq.SpecialId == i.SpecialId
&& (etatIds.Contains(eq.SasEquEtat))
select eq
).ToList()
};
var listWithListEquipements = queryWithListEquipements.ToList();
foreach (var anonymousItem in listWithListEquipements)
{
var ins = anonymousItem.Ins;
ins.Equipements = anonymousItem.EquipementsTemp;
ins.NumberEquipements = ins.Equipements.Count();
liste.Add(ins);
}
return liste;
By the way, this is very very fast (even the listing of Equipements). So this is working exactly has I wished. Thanks again for your help everyone!
Use an anonymous type. EF does not like to instantiate entity classes inside a query.
var results = (from i in query
select new
{
NbrEquipements= (from e in RepoEquipement
where e.InstallationSpecialId == i.SpecialId
&& (etatIds.Contains(e.EquEtat))
select e.SasId
).Count()
})
.ToList();
Notice how I used select new instead of select new Installation.
You can then use the data inside the list (which is now in memory) to create instances of type Installation if you want like this:
var installations = results.Select(x =>
new Installation
{
NbrEquipements = x.NbrEquipements
}).ToList();
Here is how to obtain the list of equipment for each installation entity:
var results = (from i in query
select new
{
Installation = i,
Equipment = (from e in RepoEquipement
where e.InstallationSpecialId == i.SpecialId
&& (etatIds.Contains(e.EquEtat))
select e).ToList()
})
.ToList();
This will return a list of anonymous objects. Each object will contain a property called Installation and another property called Equipment (which is a list). You can easily convert this list (of anonymous objects) to another list of whatever type that you want.
In my stored procedure, I have two select statement based on two result set i would like to get the details using linq with c# code.
Below is my Stored Procedure :
Create Proc SP_GetResult
As
Begin
Select Id,Name from EmployeeTable;
Select ContactNo,DateOfBirth from Customer;
End
I tried below code to call Stored Procedure using Linq :
Public void SelectValues()
{
using (Entities1 entity = new Entities1())
{
var list = entity.SP_GetResult
foreach (var test in list)
{
var test12123 = test;
}
}
}
I can get only EmployeeTable details. But, I can't get Customer table details.
How to do it ?
Any idea ?
It's achievable, there is a great explanation in MSDN . Check this article, it shows two ways to achieve it:
https://msdn.microsoft.com/en-us/data/jj691402.aspx
For Your requirements use approach 2 (Multiple Result Sets with Configured in EDMX).
Once You do this You can use those results with Linq without a problem.For example
Public void SelectValues()
{
using (Entities1 entity = new Entities1())
{
var Employees = entity.SP_GetResult;
var Customers = Employees.GetNextResult<Customer>();
// do your stuff
}
}
To 'join' those 2 collection You can use a Tuple Collection
Tuple<EmployeeTable, Customer>
Since the above approach works only for .NET 4.5 and higher, you can use the first approach from the article. It also suits you. You can use linq there. Look at my example:
public List<EmployeeTable> GetEmployees()
{
using(var ctx = new myEntities())
{
var cmd = ctx.Database.Connection.CreateCommand();
cmd.CommandText = "[dbo].[SP_GetResult]";
var reader = cmd.ExecuteReader();
//reader.NextResult(); <- uncomment this to get second result(Customer)
var employees = ((IObjectContextAdapter)db)
.ObjectContext
.Translate<EmployeeTable>(reader, "EmployeeTable", MergeOption.AppendOnly);
return employees;
}
Now You can use linq like:
var boss = GetEmployees().FirstOrDefault(x => x.Name == "BossName");
Alternative:
Actually to do such simple queries You don't need to have it in one sp. You don't even need store procedures for this. Having only EF You can get it like this:
using (var ctx = new myEntities())
{
var employyes = from x in ctx.EmployeeTable select new
{
id = x.Id,
name = x.Name
}
}
I just have a very simple situation where all I need is to delete record using Linq2Entities. I tried to do some research and still can't figure out the right way to do it.
Here's my simple code:
[DataObjectMethod(DataObjectMethodType.Delete)]
public void DeleteEmployee(Employee z)
{
using (var ctx = new MyEntity())
{
var x = (from y in ctx.Employees
where y.EmployeeId == z.EmployeeId
select y).FirstOrDefault();
ctx.DeleteObject(x);
ctx.SaveChanges();
}
}
[DataObjectMethod(DataObjectMethodType.Select)]
public List<Employee> GetAllEmployee()
{
using (var ctx = new MyEntity())
{
var x = from y in ctx.Employees
select y;
return x.ToList();
}
}
I can delete a particular record if for example I assign y.EmployeeName == "Harold Javier" to the Delete method above, but when I assign y.EmployeeId == z.EmployeeId to the above code, the delete doesn't work. (Note: EmployeeId is the primary key of the Employee table)
I think this is better option of delete
using (var ctx = new MyEntity())
{
var x = (from y in ctx.Employees
orderby y.EmployeeId descending
select y).FirstOrDefault();
ctx.Employees.Remove(x);
ctx.SaveChanges();
}
at my side DeleteObject is not working so i use Remove
you first need to verify that if a record exists before you actually delete it;
[DataObjectMethod(DataObjectMethodType.Delete)]
public void DeleteEmployee(Employee z)
{
using (var ctx = new MyEntity())
{
var x = (from y in ctx.Employees
where y.EmployeeId == z.EmployeeId
select y).FirstOrDefault();
if(x!=null)
{
ctx.Employees.DeleteObject(x);
ctx.SaveChanges();
}
}
}
Always check for nulls, before you delete something. Because a user may change the Id (at querystring) and try different combinations.
The above answer may be outdated... The DeleteObject method does not seem to exist in the current version of ENtity Framework. I had to use the Remove method.
var delobj = db.mytable.Where(p => p.ServiceLocation == serviceLocationID).SingleOrDefault();
db.myTable.Remove(delobj);
#Harold, I know this post is quite old, but I feel it is important to address your original question and answer. Your solution may have worked in your situation, but there are a couple of problems.
First, your original code was selecting the record to delete based on a passed in parameter. Your solution is deleting the record with the largest EmployeeId. That might be what you wish, but not likely.
The second issue is that two database accesses are required to accomplish the delete. The first is get the entity to delete the second to actually perform the delete.
The following code snippet will eliminate the need to to the read and will delete employee "z". This should yield the desired result and perform much better.
public void DeleteEmployeeId(Employee z)
{
using (var ctx = new MyEntityContext())
{
var x = new Employee{ EmployeeId = z.EmployeeId };
ctx.Entry(x).State = EntityState.Deleted;
ctx.SaveChanges();
}
}
I decided to answer my own question.
My delete function worked when I did the following:
using (var ctx = new MyEntity())
{
var x = (from y in ctx.Employees
orderby y.EmployeeId descending
select y).FirstOrDefault();
ctx.Employees.DeleteObject(x);
ctx.SaveChanges();
}
I know there could be a better approach than this, but it works for me for the mean time.
The following worked for me:
MyList.RemoveAll(x => x.MyField == 0);
This is probably because the context is different on each request (var ctx = new MyEntity()). Try using this
public static class ObjectContextPerHttpRequest
{
public static TestCasesModelContainer Context
{
get
{
string objectContextKey = HttpContext.Current.GetHashCode().ToString("ObjectContextPerHttpRequest");
if (!HttpContext.Current.Items.Contains(objectContextKey))
{
HttpContext.Current.Items.Add(objectContextKey, new TestCasesModelContainer());
}
return HttpContext.Current.Items[objectContextKey] as TestCasesModelContainer;
}
}
}
And delete is like
public static void Delete(Testcase tc)
{
var db = ObjectContextPerHttpRequest.Context;
db.DeleteObject((from p in db.TestcaseSet
where p.Id == tc.Id
select p).Single());
db.SaveChanges();
}
Here's my situation - I've got a DB which has some tables named recipes, ingredients and recipes_ingredients.
Recipes are composed of 1+ ingredients.
The recipes_ingredients has FKs between the recipes and ingredients table.
The classes that get generated are recipe and ingredient and recipe has a navigation property that looks like so:
public virtual ICollection<ingredients> ingredients { get; set; }
Great, I understand that I get a generated recipe class and a generated ingredient class and that the recipes_ingredients table doesn't get a class generated since EF views this simply as a navigation property.
Now, I've got a function called SetIngredientsForRecipe that looks like so (minus the try-catch code for brevity's sake:
public void SetIngredientsForRecipe(long recipeId, List<string> ingredients)
{
using (var db = new FoodEntities(ConnectionString, null, null))
{
var existing = GetCurrentIngredients(recipeId);
var toRemove = existing.Except(ingredients);
var toAdd = ingredients.Except(existing);
var recipe = db.recipes.Where(r => r.Id == recipeId).FirstOrDefault();
foreach (var name in toRemove)
{
var entry = recipe.ingredients.Where(i => i.Name == name).FirstOrDefault();
recipe.ingredients.Remove(entry);
}
foreach (var name in toAdd)
{
var entry = db.ingredients.Where(i => i.Name == name).FirstOrDefault();
recipe.ingredients.Add(entry);
}
db.SaveChanges();
}
}
The intent, as the name suggests, is to update the ingredient list for the given recipe to only whatever is in the list. I'm still getting comfortable with EF and wondering if there's a better (more efficient?) way to accomplish what I'm trying to do.
Follow-up:
Following the suggestions by ntziolis below, I opted to use
recipe.ingredients.Clear() to clear out whatever was in the recipe/ingredient mapping and then use the mocking that was mentioned to quickly add the new ones. Something like this:
foreach (var name in ingredients)
{
// Mock an ingredient since we just need the FK that is referenced
// by the mapping table - the other properties don't matter since we're
// just doing the mapping not inserting anything
recipe.ingredients.Add(new Ingredient()
{
Name = name
});
}
and this works very nicely.
General performance guidelines are:
try to deal with id's only
mock entities whenever possible, rather than retrieving them from db
use the new features of EF4 like Contains in order to simplify and speed up your code
Based on these principles here is a optimized (not simpler though) solution to your problem:
public void SetIngredientsForRecipe(long recipeId, List<string> ingredients)
{
using (var db = new FoodEntities(ConnectionString, null, null))
{
var recipe = db.recipe.Single(r => r.ID == recipeId);
// make an array since EF4 supports the contains keyword for arrays
var ingrArr = ingredients.ToArray();
// get the ids (and only the ids) of the new ingredients
var ingrNew = new HasSet<int>(db.ingrediants
.Where(i => ingrArr.Contains(i.Name))
.Select(i => I.Id));
// get the ids (again only the ids) of the current receipe
var curIngr = new HasSet<int>(db.receipes
.Where(r => r.Id == recipeId)
.SelectMany(r => r.ingredients)
.Select(i => I.Id));
// use the build in hash set functions to get the ingredients to add / remove
var toAdd = ingrNew.ExpectWith(curIngr);
var toRemove = curIngr.ExpectWith(ingrNew);
foreach (var id in toAdd)
{
// mock the ingredients rather than fetching them, for relations only the id needs to be there
recipe.ingredients.Add(new Ingredient()
{
Id = id
});
}
foreach (var id in toRemove)
{
// again mock only
recipe.ingredients.Remove(new Ingredient()
{
Id = id
});
}
db.SaveChanges();
}
}
If you want it simpler you could just clear all ingredients and re add them if necessary, EF might even be clever enough to figure out that the relations haven't changed, not sure about it though:
public void SetIngredientsForRecipe(long recipeId, List<string> ingredients)
{
using (var db = new FoodEntities(ConnectionString, null, null))
{
var recipe = db.recipe.Single(r => r.ID == recipeId);
// clear all ingredients first
recipe.ingredients.Clear()
var ingrArr = ingredients.ToArray();
var ingrIds = new HasSet<int>(db.ingrediants
.Where(i => ingrArr.Contains(i.Name))
.Select(i => I.Id));
foreach (var id in ingrIds)
{
// mock the ingredients rather than fetching them, for relations only the id needs to be there
recipe.ingredients.Add(new Ingredient()
{
Id = id
});
}
db.SaveChanges();
}
}
UPDATE
Some coding errors have been corrected.
You can condense your Where clauses with the FirstOrDefault calls:
recipe.ingredients.FirstOrDefault(i => i.Name == name);
Though I personally prefer to use SingleOrDefault though I'm not sure what the difference is exactly:
recipe.ingredients.SingleOrDefault(i => i.Name == name);
Also, since the ingredient list that is passed in is a List<string> (as opposed to a list of ingredient IDs), it sort of implies that new ingredients may also be created as part of this process, which isn't handled (though may have been left out for brevity).