Read only when updating db records - c#

"Property or indexer cannot be assigned to -- it is read only"
i see a lot of similar question though none actually seem to help me.
i am updating some rows in my db.
first i call my data:
var projects = (from p in _ProjectRep.GetAll()
join cl in _ClientRepo.GetAll() on p.ClientID equals cl.ClientID
where p.IsOpen == true && p.Tasks.Any(t => t.TimeEntries.Any(te => te.DateEntity >= dateLimit)) == false && p.Tasks.Any(te => te.TimeEntries.Any())
select new {
TickProjectID = p.TickProjectID,
ClientName = cl.ClientName,
ProjectName = p.ProjectName,
IsOpen = p.IsOpen,
DateClosed = p.DateClosed
}).ToList();
Then i try to loop through that data, and update specific fields in those records.
foreach (var item in projects)
{// Update projects to closed.
item.IsOpen = false;
item.DateClosed = DateTime.Now;
}
and lastly save the data..
// updates changes to OUR db.
var affectedCount = _UnitOfWork.SaveChanges();
But i keep getting that error, and i do not know what to do about it.
What i can read it is something about get/set, but i have none of those,
and i cannot see why those should be nessesary ?
Hoping someone can give a clear solution, that might help me.
Edit
private readonly ProjectRepository _ProjectRep;
_ProjectRep = new ProjectRepository(unitOfWork);

var projects = (from p in _ProjectRep.GetAll()
join cl in _ClientRepo.GetAll() on p.ClientID equals cl.ClientID
where p.IsOpen == true && p.Tasks.Any(t => t.TimeEntries.Any(te => te.DateEntity >= dateLimit)) == false && p.Tasks.Any(te => te.TimeEntries.Any())
select p).ToList();
Try this. Problem in your code is, that you are working with anonymous type (created using new {...}). This type doesn't know anything like change tracking, its properties are read only, so this type can not be used to save changes to database.

it seems my sql call was anonymous, and therefore it did not know what it was.
i changed my sql call select
var projects = (from p in _ProjectRep.GetAll()
join cl in _ClientRepo.GetAll() on p.ClientID equals cl.ClientID
where p.IsOpen == true && p.Tasks.Any(t => t.TimeEntries.Any(te => te.DateEntity >= dateLimit)) == false && p.Tasks.Any(te => te.TimeEntries.Any())
select new {
Project = p,
ClientName = cl.ClientName
}).ToList();
and then i just have to call "Project.{something}" when i wanted to select data.
like this:
foreach (var item in projects)
{// Update projects to closed.
item.Project.IsOpen = false;
item.Project.DateClosed = DateTime.Now;
}
that made the whole thing work.

Related

Update IQueryable result before using as join in next query

I need to use Linq to Entity Framework to query a LOCATION table to get the record of the location code with the MAX effective date, then use that result as a join in the next query.
I BELIEVE I need to do convert before the IQueryable is used, because I have that last clause in the second query where I want to exclude records where the FLOOR code is in the excludedSchools list. That excludedSchools list will have the newLocationCode in it.
So, I need to update the values in the IQueryable result before I use it. Can I do this? Here is my code:
using (var db = new TheContext())
{
IQueryable<LocationTable> locatinWithMaxEffDate =
(from lc in db.LocationTable
where lc.EFF_STATUS == "A" && lc.EFFDT <= DateTime.Now
group lc by lc.LOCATION into g
select g.OrderByDescending(x => x.EFFDT).FirstOrDefault()
);
foreach (var location in locatinWithMaxEffDate.ToList())
{
string newLocationCode;
if(codeMappingDictionary.TryGetValue(location.FLOOR, out newLocationCode))
{
// how do I update locatinWithMaxEffDate FLOOR value
// with newLocationCode so it works in the query below?
location.FLOOR = newLocationCode;
}
}
var query =
(from fim in db.PS_PPS_FIM_EE_DATA
join mloc in locatinWithMaxEffDate on fim.LOCATION equals mloc.LOCATION
where
fim.EMPL_STATUS == PsPpsFimEeData.EmployeeStatusValues.Active
&& fim.AUTO_UPDATE == PsPpsFimEeData.AutoUpdateValues.Enabled
&& includeJobCodes.Contains(fim.JOBCODE)
&& !excludedSchools.Contains(mloc.FLOOR)
select new PpsAdministratorResult
{
SchoolId = mloc.FLOOR,
Login = fim.OPRID,
EmployeeId = fim.EMPLID,
}
With the code above, the locatinWithMaxEffDate does not have the updated FLOOR values. I can see why this is, but can't seem to fix it.
So far, I have tried introducing another list to ADD() the new location record to, then casting that as an IQueryable, but I get an error about primitive vs concrete types.
I decided to make things easier on myself. Since both sets of data are very small (fewer than 1000 records each) I call take the entire set of data as an annonymous type:
using (var db = new TheContext())
{
IQueryable<LocationTable> locatinWithMaxEffDate =
(from lc in db.LocationTable
where lc.EFF_STATUS == "A" && lc.EFFDT <= DateTime.Now
group lc by lc.LOCATION into g
select g.OrderByDescending(x => x.EFFDT).FirstOrDefault()
);
var query =
(from fim in db.PS_PPS_FIM_EE_DATA
join mloc in locatinWithMaxEffDate on fim.LOCATION equals mloc.LOCATION
where
fim.EMPL_STATUS == PsPpsFimEeData.EmployeeStatusValues.Active
&& fim.AUTO_UPDATE == PsPpsFimEeData.AutoUpdateValues.Enabled
&& includeJobCodes.Contains(fim.JOBCODE)
select new PpsAdministratorResult
{
SchoolId = mloc.FLOOR,
Login = fim.OPRID,
EmployeeId = fim.EMPLID,
}
}
Then, just work with the two objects:
List<PpsAdministratorResult> administratorList = new List<PpsAdministratorResult>();
foreach (var location in query.ToList())
{
string newLocationCode;
if(schoolCodeMappings.TryGetValue(location.SchoolId, out newLocationCode)) // && newLocationCode.Contains(location.LOCATION))
{
location.SchoolId = newLocationCode;
}
if( !excludedSchools.Contains(location.SchoolId) )
{
administratorList.Add(location);
}
}
Now, I have the list I want.

passing linq anonymous result to iqueryable object for another query

I have two tables (tbPerson and tbDataLog) where I need to return Id from one table (tbPerson) after checking certain conditions on both. After this, this result should be passed to another query. My first query returns the Id (primary key of a table) successfully and I need to pass these ids to another query so that it return me data based upon these Id. I also has an IQueryable type base object to check certain conditions to fetch data.
IQueryable<tbPerson> dataset
and I cannot changes this from Iqueryable to other as it will break other part of the code)
My first linq statement:
public static IQueryable<LogResults> GetResultsForYes()
{
Databasename ents = new Databasename();
var ids = (from f in ents.tbPerson
join g in ents.tbDataLog
on f.InfoID equals g.RefId
where g.Tag == "subscribed" && g.OldValue == "No" && g.Action == "Modified"
select new LogResults { _LogID = f.Id }).OrderBy(x => x._LogID);
return ids;
}
public class LogResults
{
public int _LogID { get; set; }
}
I access my result something like this where I can see in debugger all the Ids.
IQueryable<LogResults> log = GetResultsForYes();
Problem comes, when I tried to get records from tbPerson based upon these returned Id.
dataset=log.where(x=>x._LogID != 0);
I get this error:
Cannot implicitly convert type 'System.Linq.IQueryable' to 'System.Linq.IQueryable'. An explicit conversion exists(are you missing a cast)?
Any suggestions or some other good approach is welcome.
I love this thing about stackoverflow. when we write questions we force our brain to think more deeply and after 30 mins of posting this question, I solved it in a simple way. Sometimes we overcomplicated things!
var ids = (from f in ents.tbPerson
join g in ents.tbDataLog
on f.InfoID equals g.RefId
where g.Tag == "subscribed" && g.OldValue == "No" && g.Action == "Modified"
select new { f.Id }).ToArray();
var allId = ids.Select(x => x.Id).ToArray();
dataset = dataset.Where(x => allId.Contains(x.Id));
#ankit_sharma : I have not tested yours but will give a try and come back to you. Thanks for giving time and effort.
IQueryable<tbPerson> dataset=log.where(x=>x._LogID != 0);
The result of log.where(x=>x._LogID != 0) is an IQueryable<LogResults>, and you are trying to assign this result to dataset of type IQueryable<tbPerson>, two diferent types.
EDIT:
I see you make a join to get the tbPerson ids, and then you do a second query to get the persons. You could get the persons in the first join.
I just modify your code:
IQueryable<tbPerson> persons = from person in ents.tbPerson
join g in ents.tbDataLog
on person.InfoID equals g.RefId
where g.Tag == "subscribed" && g.OldValue == "No" && g.Action == "Modified"
select person;

How to Link two IDs from different classes in MVC5 to display certain information

I am trying to link up the RestaurantId in the RestaurantReservationEventsTbl with the RestaurantID in the RestaurantTbl to display reservations that are only made for the currently logged in restaurant.
I am receiving the following error in my code operator == cannot be applied to operands of type int and iqueryable int
Here is what I am doing in my home controller
var RestaurantIDRestaurantTbl = from r in db.Restaurants select r.RestaurantID;
//var listOfRestaurantsReservations = db.RestaurantReservationEvents.ToList();
var listOfRestaurantsReservations = db.RestaurantReservationEvents.Where(x => x.RestaurantID == RestaurantIDRestaurantTbl).ToList();
//return View(restaurants.Where(x => x.RestaurantEmailAddress == UserEmail).ToList());
//create partial view called _RestaurantReservation
return PartialView("_RestaurantReservations", listOfRestaurantsReservations);
You have to change your code to materialize the restaurantIds like this:
var RestaurantIDRestaurantTbl = (from r in db.Restaurants
select r.RestaurantID).ToList();
Then you may change the code as below for the comparison to work:
var listOfRestaurantsReservations = db.RestaurantReservationEvents.Where(x => RestaurantIDRestaurantTbl.Contains(x.RestaurantID)).ToList();
Anyway this is not the best solution. I will write another example for you, just try this example if it is working or not and let me know for the result.
I would considering changing the code as below to be much more efficient:
var listOfRestaurantsReservations = (from r in db.Restaurants
join e in db.RestaurantReservationEvents
on r.RestaurantID equals e.RestaurantID
//where r.RestaurantID == something //if where condition needed
select e).ToList();
If your tables are not connected with foreignkeys please consider to read this documentation here to make a better structure of the tables since they are related to each-other.
If your tables are related as in documentation article you might have something like that:
var RestaurantIDRestaurantTbl = db.Restaurants.SingleOrDefault(x => x.RestaurantID == something);
if(RestaurantIDRestaurantTbl != null)
{
var listOfRestaurantsReservations = RestaurantIDRestaurantTbl.RestaurantReservationEvents.ToList();
}
{
// This will give you a list of IDs
var RestaurantIDRestaurantTbl = db.Restaurants
.Select(p => p.RestaurantID)
.ToList();
// Using .Any() is a better choice instead of .Contains()
// .Contains is used to check if a list contains an item while .Any will look for an item in a list with a specific ID
var listOfRestaurantsReservations = db.RestaurantReservationEvents
.Where(p => RestaurantIDRestaurantTbl.Any(r => r.pRestaurantID == p))
.ToList();
}

LINQ - using result from one in another

I'm completely new to LINQ, i want to rewrite some of mine SQL querys into LINQ (just to learn) and i'v already stuck at the beginning. Probably solution is very simple but as i'v said I'm completely new and i didn't find solution to this.
I have one query :
string typMoneta = textBox1.Text;
var moneta = from x in db.grupyTowarowes
where x.typ == typMoneta
select new
{
x.grupa
};
Which works ok and when i set
dataGridView1.DataSource = moneta;
Then i got output
And i want to use this output in my second query :
var query = from c in dbContext.Picking
where c.Number == 1000 && c.Group == moneta
select new
{
c.id
};
Problem is with c.Group == moneta. I don't know the correct syntax. Could someone help me?
I think you meant to use moneta.Contains(c.Group). In first query, make sure you use ToList() to load data into memory.
IList<string> moneta = (from x in db.grupyTowarowes
where x.typ == typMoneta
select x.grupa).ToList();
var query = (from c in dbContext.Picking
where c.Number == 1000 && moneta.Contains(c.Group)
select c.id).ToList();
The moneta is an IEnumerable<T> where T in your case is the type of grupa
That being said you should write your query like below:
var query = from c in dbContext.Picking
where c.Number == 1000
&& moneta.Contais(c.Group)
select new
{
c.id
};
or in fluent syntax like below:
var query = dbContext.Picking
.Where(pick => pick.Number == 1000
&& moneta.Contains(pick.Group))
.Select(pick => pick.id);
Note that moneta is not a collection of strings. It's a collection of objects that have a string property named "grupa".
Does this work for you?
var query =
from c in dbContext.Picking
where c.Number == 1000
&& moneta.Any(m => m.grupa == c.Group)
select new { c.id };
You could also do this:
// Get list of strings
var groups = moneta.Select(m => m.grupa).ToList();
// Get items where "Group" value is one of the strings in groups list, above.
var query =
from c in dbContext.Picking
where c.Number == 1000
&& groups.Contains(c.Group)
select new { c.id };

linq query from two database

I have a linq query from two database, however, each time the program stops at the query point. I don't know how to debug linq using VS. Can someone help me figure it out what's wrong here? Thank you.
public List<Promotion> GetBroder(string source)
{
string _connString = ConfigurationManager.AppSettings["DB1"];
PromotionDataContext dc = new PromotionDataContext(_connString);
string connString = ConfigurationManager.AppSettings["DB2"];
ReachDirectDataContext RDdc = new ReachDirectDataContext(connString);
return (from b in RDdc.BrokerNos
from p in dc.Promotions
where p.Source == source && p.Broker == b.BrokerNo1
select new Promotion() {Code=p.Code,BrokerName=b.Name}).ToList<Promotion>();
}
Your linq statement looks fine. To aid in debugging, I find it helpful to assign the linq query to a local variable, then return the local variable. You can then set a breakpoint on the return statement, and when the debugger stops at the breakpoint, you can inspect the query local variable to see what's in it, interactively. You can use the Locals window in VS, or the Immediate Window to surf around inside your app's variables and see what's going on.
In particular, double check that the inputs into your linq query are actually providing data. Verify that RDdc.Brokernos is non-empty, and dc.Promotions, etc. If these are empty, the result will be empty. Track your bug "upstream".
Minor point: You don't need to specify the type parameter on the .ToList() call in the select. The compiler will infer the type automagically.
You can use the following to display the generated SQL for the Linq statement.
ReachDirectDataContext RDdc = new ReachDirectDataContext(connString);
RDdc.Log = Console.Out;
return (from b in RDdc.BrokerNos
from p in dc.Promotions
where p.Source == source && p.Broker == b.BrokerNo1
select new Promotion() {Code=p.Code,BrokerName=b.Name}).ToList<Promotion>();
You can try the following to separate out the queries.
var promotions = from p in dc.Promotions
where p.Source == source
select p;
var brokers = from o in promotions
join b in RDdc.BrokerNos on o.Broker equals b.BrokerNo1
select new Promotion
{
Code = o.Code,
BrokerName = b.Name
};
return brokers.ToList();
The double from looks suspicious to me.
(This is not the equivalent to SQL's JOIN statement, if that is what you were aiming for.)
If you can combine the contexts:
Try creating relationship between BrokerNos and Promotions in edmx and using navigation property in query.
For example:
var result = dc.Promotions.Where(p => p.Source == source).
Select(p => new Promotion() {
Code = p.Code,
BrokerName = p.Broker.Name, // use new navigation property here
});
If not (intersection will be done in memory, not on DB!!!:
var result1 = dc.Promotions.Where(p => p.Source == source).
Select(p => new Promotion() {
Code = p.Code,
BrokerId = p.BrokerId, // add id property for intermediate results
}).ToList();
var result2 = RDdc.Brokers.ToList();
var finalResult = result1.Where(p => result2.Contains(b => b.BrokerId == p.BrokerId)).Select(p => new Promotion{
Code = p.Code,
BrokerName = result2.Single(b => b.BrokerId == p.BrokerId).Name,
});

Categories