SaveChanges() only affects one row - linq

I want to delete some records and I tried using the following code:
if (objDetail != null)
{
objContext.DetailVouchers.RemoveRange(
objContext.DetailVouchers.Where(t => t.REFNO == strRefNo));
objContext.SaveChanges();
}
But it only deleted the last record and not all of them.
My Context Class is
class MainContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//base.OnModelCreating(modelBuilder);
Database.SetInitializer<MainContext>(null);
modelBuilder.Entity<MainVoucher>().ToTable("TBL_ACC_VOUCHER_MAIN");
modelBuilder.Entity<MainVoucher>().HasKey(t => new { t.REFNO });
modelBuilder.Entity<DetailVoucher>().ToTable("TBL_ACC_VOUCHER_DETAIL");
modelBuilder.Entity<DetailVoucher>().HasKey(t => new { t.REFNO });
}
}
and create context class object like
MainContext objContext = new MainContext();

You have to make your list of items to delete before using RemoveRange.
try reza's solution with ToList() on the first line :
var items = objContext.DetailVouchers.Where(t => t.REFNO == strRefNo).ToList();
objContext.DetailVouchers.RemoveRange(items);
context.SaveChanges();

Try this.[EDIT]
var items = objContext.DetailVouchers.Where(t => t.REFNO == strRefNo);
objContext.DetailVouchers.RemoveRange(items);
context.SaveChanges();

Related

how to declare var keyword for variable globally in mvc controller

I want to declare var keyword in globally for the variable in mvc controller
Because I am using that variable at multiple times thats why I want to use that variable as a globally.
But I dont know that how var is been done by globally because var is different type as per string, int, decimal to place in globally.
For more clear lets see the code
var query = new List<T>();
if (model.CategoryId == -1)
{
query = _Db.Purchase.Where(w => w.IsIncludeIntoStock == true).ToList().GroupBy(x => new { x.ManufacturerId, x.CategoryId, x.Weight, x.WeightTypeId }).ToList();
}
else
{
query = _Db.Purchase.Where(w => w.IsIncludeIntoStock == true && w.CategoryId == model.CategoryId).ToList().GroupBy(x => new { x.ManufacturerId, x.CategoryId, x.Weight, x.WeightTypeId }).ToList();
}
var dataList = (from x in query
select new
{
})
Now, here query variable is used many times in code. Now, I want to declare globally this query variable. This is the latest code that I tried. In this error is showing by giving red line in code.
Firstly, your "Global" definition isn't clear. Do you want to use "query" instance for one Class or want to use for all class that generated by one class.
Secondly if you want to use as Global, you should define your global variable like this
List<dynamic> query=new List<dynamic>();
of course this kind of approach is not healthy way (dynamic using with c#)
By the way, you can't use "var" keyword in out of functions. You have to use certain type of variable destination in class level.
Define Variable in Class Level
In the given piece of code, I try to define global variable at class level.
public class MyTestClass
{
List<dynamic> query=new List<dynamic>();
public MyTestClass()
{
}
public void generateQuery()
{
if (model.CategoryId == -1)
{
query = _Db.Purchase.Where(w => w.IsIncludeIntoStock == true).ToList().GroupBy(x => new { x.ManufacturerId, x.CategoryId, x.Weight, x.WeightTypeId }).ToList();
}
else
{
query = _Db.Purchase.Where(w => w.IsIncludeIntoStock == true && w.CategoryId == model.CategoryId).ToList().GroupBy(x => new { x.ManufacturerId, x.CategoryId, x.Weight, x.WeightTypeId }).ToList();
}
var dataList = (from x in query
select new
{
})
}
}
}
Let's let try to cover another approach.
Use The Generated Class's Variable As Global Variable
At this time you can define your global variable in ancestor class
public class MyAncestorClass
{
List<dynamic> query=query=new List<dynamic>();
}
public class MyChildClass:MyAncestorClass
{
public void generateQuery()
{
if (model.CategoryId == -1)
{
query = _Db.Purchase.Where(w => w.IsIncludeIntoStock == true).ToList().GroupBy(x => new { x.ManufacturerId, x.CategoryId, x.Weight, x.WeightTypeId }).ToList();
}
else
{
query = _Db.Purchase.Where(w => w.IsIncludeIntoStock == true && w.CategoryId == model.CategoryId).ToList().GroupBy(x => new { x.ManufacturerId, x.CategoryId, x.Weight, x.WeightTypeId }).ToList();
}
var dataList = (from x in query
select new
{
})
}
}
}

Call custom function in EF LINQ query Where clause

Env: EF6 + Code First
I want to be able to call a custom function in the Where clause of a LINQ query
So this line:
var activeStaff = Repo.Staff.Where(s => s.EndDate == null || s.EndDate.Value > DateTime.Today);
becomes:
var activeStaff = Repo.Staff.Where(s => MyEdmFunctions.IsCurrentStaff(s));
This is what I have tried,
public class MyContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(new MyCustomConvention());
}
}
public class MyCustomConvention : IConceptualModelConvention<EdmModel>
{
public void Apply(EdmModel item, DbModel model)
{
var boolType = PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Boolean);
var staffType = item.EntityTypes.Single(e => e.Name == "Staff");
var payLoad = new EdmFunctionPayload
{
ParameterTypeSemantics = ParameterTypeSemantics.AllowImplicitConversion,
IsComposable = true,
IsNiladic = false,
IsBuiltIn = false,
IsAggregate = false,
IsFromProviderManifest = true,
Parameters = new[] { FunctionParameter.Create("Staff", staffType, ParameterMode.In) },
ReturnParameters = new[] { FunctionParameter.Create("ReturnType", boolType, ParameterMode.ReturnValue) }
};
var function = EdmFunction.Create("IsCurrentStaff", "My.Core.Data", DataSpace.CSpace, payLoad, null);
item.AddItem(function);
}
}
public static class MyEdmFunctions
{
[DbFunction("My.Core.Data", "IsCurrentStaff")]
public static bool IsCurrentStaff(Staff s)
{
return s.EndDate == null || s.EndDate > DateTime.Today;
}
}
But I'm getting "Specified method is not supported." error from EntityFramework's internal CTreeGenerator class (after decompilation)
public override DbExpression Visit(NewRecordOp op, Node n)
{
throw new NotSupportedException();
}
Can someone please confirm if there is really no way to call a custom function in the where clause?
I know it's possible to create a stored procedure and map it in the model. But is there a way to write it in C#?
Thanks.
Just to answer my own question:
I'm going to follow this thread to create a AndAlso expression to solve my problem.
Extension method in where clause in linq to Entities

How to convert this EF Cloning Code to use DBContext instead of EntityObject?

I need to clone Master and Child Entities. I have come across this solution on CodeProject which seems to do the job, see: http://www.codeproject.com/Tips/474296/Clone-an-Entity-in-Entity-Framework-4.
However I am using EF5 and DBContext whereas this code is using EF4 and EntityObject, so I am wondering what changes I need to make to it?
The code is:
public static T CopyEntity<T>(MyContext ctx, T entity, bool copyKeys = false) where T : EntityObject
{
T clone = ctx.CreateObject<T>();
PropertyInfo[] pis = entity.GetType().GetProperties();
foreach (PropertyInfo pi in pis)
{
EdmScalarPropertyAttribute[] attrs = (EdmScalarPropertyAttribute[])
pi.GetCustomAttributes(typeof(EdmScalarPropertyAttribute), false);
foreach (EdmScalarPropertyAttribute attr in attrs)
{
if (!copyKeys && attr.EntityKeyProperty)
continue;
pi.SetValue(clone, pi.GetValue(entity, null), null);
}
}
return clone;
}
The calling code is:
Customer newCustomer = CopyEntity(myObjectContext, myCustomer, false);
foreach(Order order in myCustomer.Orders)
{
Order newOrder = CopyEntity(myObjectContext, order, true);
newCustomer.Orders.Add(newOrder);
}
I am posting here as the feedbacks on this post look inactive and I am sure this is a question that could be answered by any EF pro.
Many thanks in advance.
If you want a clone of an entity using EF5 DbContext the simplest way is this:
//clone of the current entity values
Object currentValClone = context.Entry(entityToClone)
.CurrentValues.ToObject();
//clone of the original entity values
Object originalValueClone = context.Entry(entityToClone)
.OriginalValues.ToObject();
//clone of the current entity database values (results in db hit
Object dbValueClone = context.Entry(entityToClone)
.GetDatabaseValues().ToObject();
your code will be work only if in your entity property has EdmScalarPropertyAttribute
alternatively you can use MetadataWorkspace to get entity property
public static class EntityExtensions
{
public static TEntity CopyEntity<TEntity>(DbContext context, TEntity entity, bool copyKeys = false)
where TEntity : class
{
ObjectContext ctx = ((IObjectContextAdapter)context).ObjectContext;
TEntity clone = null;
if (ctx != null)
{
context.Configuration.AutoDetectChangesEnabled = false;
try
{
clone = ctx.CreateObject<TEntity>();
var objectEntityType = ctx.MetadataWorkspace.GetItems(DataSpace.OSpace).Where(x => x.BuiltInTypeKind == BuiltInTypeKind.EntityType).OfType<EntityType>().Where(x => x.Name == clone.GetType().Name).Single();
var pis = entity.GetType().GetProperties().Where(t => t.CanWrite);
foreach (PropertyInfo pi in pis)
{
var key = objectEntityType.KeyProperties.Where(t => t.Name == pi.Name).FirstOrDefault();
if (key != null && !copyKeys)
continue;
pi.SetValue(clone, pi.GetValue(entity, null), null);
}
}
finally
{
context.Configuration.AutoDetectChangesEnabled = true;
}
}
return clone;
}
}

Compare 2 lists using linq

I'm a linq noob.... can someone please some me how to achieve this using linq... I'm trying to compare 2 lists in both directions...
internal void UpdateUserTeams(int iUserID)
{
UserTeamCollection CurrentTeams = GetUserTeams(iUserID);
UserTeamCollection UpdatedTeams = this;
foreach (UserTeam ut in CurrentTeams)
{
if(!UpdatedTeams.ContainsTeam(ut.ID))
{
RemoveTeamFromDB();
}
}
foreach (UserTeam ut in UpdatedTeams)
{
if (!CurrentTeams.ContainsTeam(ut.ID))
{
AddTeamToDB();
}
}
}
public bool ContainsTeam(int iTeamID)
{
return this.Any(t => t.ID == iTeamID);
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Linqage
{
class Program
{
static void Main(string[] args)
{
UserTeamCollection currentTeams = new UserTeamCollection()
{
new UserTeam(1),
new UserTeam(2),
new UserTeam(3),
new UserTeam(4),
new UserTeam(5)
};
UserTeamCollection updatedTeams = new UserTeamCollection()
{
new UserTeam(2),
new UserTeam(4),
new UserTeam(6),
new UserTeam(8)
};
currentTeams.Except(updatedTeams).All(u =>
{
//Console.WriteLine("Item ID: {0}",u.ID);
//RemoveFromDB()
return true;
});
updatedTeams.Except(currentTeams).All(u =>
{
//Console.WriteLine("Item ID: {0}", u.ID);
//AddToDB()
return true;
});
}
}
public class UserTeamCollection
: List<UserTeam>
{
}
//Either overwrite the GetHashCode and Equals method OR create a IComparer
public class UserTeam
{
public int ID { get; set; }
public UserTeam(int id)
{
ID = id;
}
public override bool Equals(object obj)
{
UserTeam iOther = obj as UserTeam;
if (iOther != null)
{
return this.ID == iOther.ID;
}
return false;
}
public override int GetHashCode()
{
return ID.GetHashCode();
}
}
}
So converting your initial question to an english requirement:
foreach (UserTeam ut in CurrentTeams) // for each current team
{
if(!UpdatedTeams.ContainsTeam(ut.ID)) // that is not in the updated teams list
{
RemoveTeamFromDB(); // remove it from the database
}
}
foreach (UserTeam ut in UpdatedTeams) //for each of the teams in the updated teams list
{
if (!CurrentTeams.ContainsTeam(ut.ID)) //if the current team does not contain the updated team
{
AddTeamToDB(); //add the team to the database
}
}
Therefore, you want to do:
//select all current teams that are not in updated teams list
CurrentTeam.Except(UpdatedTeams).All(team => { RemoveTeamFromDB(team); return true; });
//select all updated teams that are not in the current teams list
UpdatedTeam.Except(CurrentTeams).All(team => { AddTeamToDB(team); return true; });
Make sure your UserTeam object has proper overrides for the Equals and GetHashCode methods, so that comparison between two UserTeams is accurate :)
You would normally use Enumerable.Except both ways to get the differences. Then add and remove as needed.
var addedTeams = UpdatedTeams.Except(CurrentTeams);
var removedTeams = CurrentTeams.Except(UpdatedTeams);
You're trying to get the outer parts from a full outer join. Here's a rough way to achieve that.
ILookup<int, UserTeam> currentLookup = CurrentTeams
.ToLookup(ut => ut.ID);
ILookup<int, UserTeam> updatedLookup = UpdatedTeams
.ToLookup(ut => ut.ID);
List<int> teamIds = CurrentTeams.Select(ut => ut.ID)
.Concat(UpdatedTeams.Select(ut => ut.ID))
.Distinct()
.ToList();
ILookup<string, UserTeam> results =
(
from id in teamIds
let inCurrent = currentLookup[id].Any()
let inUpdated = updatedLookup[id].Any()
let key = inCurrent && inUpdated ? "No Change" :
inCurrent ? "Remove" :
inUpdated ? "Add" :
"Inconceivable"
let teams = key == "Remove" ? currentLookup[id] :
updatedLookup[id]
from team in teams
select new {Key = key, Team = team)
).ToLookup(x => x.Key, x => x.Team);
foreach(UserTeam ut in results["Remove"])
{
RemoveTeamFromDB();
}
foreach(UserTeam ut in results["Add"])
{
AddTeamToDB();
}

Hierarchical structure iteration and LINQ

Assume that we have class
public class RMenuItem
{
public List<RMenuItem> ChildrenItems { get; }
public decimal OperationID { get; }
public string Name { get; }
}
as you can see - each menuitem could have children items - as usual in menu.
My task is to iterate through each items of this list and apply some action to it. Classical decision is to write recursive iteration. But I'm interesting if LINQ could make my task easier? For example, I suppose that we can write query that can get flat list of objects, which i can iterate simply with foreach. But my attempts in this way weren't successful yet.
So any help appreciated!
It's possible:
public void PrintAllNames(RMenuItem rootItem)
{
Action<RMenuItem> print = null;
print = m =>
{
Console.WriteLine(m.Name);
m.ChildrenItems.ForEach(print);
};
print(rootItem);
}
Notice how it's necessary to declare print so that print can use itself. This is directly comparable to a recursive method, which I'd rather use:
public void PrintAllNames(RMenuItem rootItem)
{
Console.WriteLine(rootItem.Name);
rootItem.ChildrenItems.ForEach(PrintAllNames);
}
(although for a more complex situation, maybe the functional solution would make the most sense)
I suggest 2 ways of achieving this. You can opt with an utility method to get all the items or you can implement the Visitor Pattern, though it implies changing the RMenuItem class.
Utility method:
static IEnumerable<RMenuItem> GetAllMenuItems(IList<RMenuItem> items)
{
if (items == null)
throw new ArgumentNullException("items");
Queue<RMenuItem> queue = new Queue<RMenuItem>(items);
while (queue.Count > 0)
{
var item = queue.Dequeue();
if (item.ChildrenItems != null)
{
foreach (var child in item.ChildrenItems)
{
queue.Enqueue(child);
}
}
yield return item;
}
}
I prefer an imperative way to a recursive because we can use iterator blocks.
Visitor Pattern:
public interface IRMenuItemVisitor
{
void Visit(RMenuItem item);
}
public class PrintRMenuItemVisitor : IRMenuItemVisitor
{
public void Visit(RMenuItem item)
{
Console.WriteLine(item);
}
}
public interface IRMenuItem
{
void Accept(IRMenuItemVisitor visitor);
}
public class RMenuItem : IRMenuItem
{
// ...
public void Accept(IRMenuItemVisitor visitor)
{
visitor.Visit(this);
if (ChildrenItems != null)
{
foreach (var item in ChildrenItems)
{
item.Accept(visitor);
}
}
}
}
Usage:
RMenuItem m1 = new RMenuItem
{
Name = "M1",
ChildrenItems = new List<RMenuItem> {
new RMenuItem { Name = "M11" },
new RMenuItem {
Name = "M12",
ChildrenItems = new List<RMenuItem> {
new RMenuItem { Name = "M121" },
new RMenuItem { Name = "M122" }
}
}
}
};
RMenuItem m2 = new RMenuItem
{
Name = "M2",
ChildrenItems = new List<RMenuItem> {
new RMenuItem { Name = "M21" },
new RMenuItem { Name = "M22" },
new RMenuItem { Name = "M23" }
}
};
IList<RMenuItem> menus = new List<RMenuItem> { m1, m2 };
foreach (var menu in GetAllMenuItems(menus))
{
Console.WriteLine(menu);
}
// or
IList<RMenuItem> menus = new List<RMenuItem> { m1, m2 };
foreach (var menu in menus)
{
menu.Accept(new PrintRMenuItemVisitor());
}
You could difine a Flatten method in your class (or as an extension if you prefer) like this
public IEnumerable<RMenuItem> Flatten()
{
foreach (var item in ChildrenItems)
{
yield return item;
}
return ChildrenItems.SelectMany(item => item.Flatten());
}
then doing somthing with each elements will be as simple as
RMenuItem rootItem ;
// do somthing with the root item
foreach (var item in rootItem.Flatten())
{
// do somthing
}
Indeed you can do that using LINQ, SelectMany flats out the list, just some example
menuItemsList.SelectMany(x => x.ChildrenItems).Where(c => c.someChildProperty);
Thanks
Edit:
In response to the comments, I was just giving an example of SelectMany previously. Thanks for pointing out.
menuItemsList.SelectMany(x => x.ChildrenItems.Select(p => p)).Where(c => c.someChildProperty);
OR something like this
menuItemsList.SelectMany(x => x.ChildrenItems).Select(p => p).Where(c => c.someChildProperty);
Edit2
Ahh .. now I understood what you want ..
We can just slightly modify my above query to do what you want
menuItemsList
.SelectMany(x => { //do something with x like printing it
x.ChildrenItems
})
.Select(p => { // do something with p like printing it
p
});
Basically you can do what you want the element inside the {}
Thanks

Resources