What I'd like to happen is that if I've already created the record (GuildName) in the session and attached it to the context,then for EF to retrieve it from the context instead of creating a duplicate, however it cant seam to make it not create a duplicate.
public static async Task ProcessNames()
{
var db = new SQLDbContext();
db.Configuration.ProxyCreationEnabled = false;
var existingNames = db.CharacterNames.Include("GuildName").Include("RealmName").Take(10).ToList();
var gatherGuildNameTaskList = (
from name in existingNames
select GetGuildFromName(name, db)).ToList();
await Task.WhenAll(gatherGuildNameTaskList);
db.SaveChanges();
}
public static async Task GetGuildFromName(CharacterName characterName, SQLDbContext db)
{
var character = await ApiHelper.GetJsonFromUrlAsync<Character>(new Uri( URL ));
if (character.Guild == null) return;
//This is the call that appears to not be working as intended
var guildName = db.GuildName.
SingleOrDefault(x => x.RealmName.Name == character.Guild.Name) ?? new GuildName
{
Name = character.Guild.Name,
CharacterNames = new List<CharacterName>(),
RealmName = characterName.RealmName
};
if (!guildName.Equals(characterName.GuildName))
{
characterName.GuildName = guildName;
}
}
I only having it take 10 names for testing, but normally there's a few 100k's
The only thing I can think is to call save changes on search method of GetGuildFromName, but I have a feeling, that it might not work as intended, but could be detrimental to performance, not that performance is a huge factor, but I like trying to practice making things perform reasonably.
I think you never add your newGuildName to the context ( db.GuildName.Add(guildName) like this:
var guildName = db.GuildName.
SingleOrDefault(x => x.RealmName.Name == character.Guild.Name);
if (guildName ==null)
{
guildName = new GuildName
{
Name = character.Guild.Name,
CharacterNames = new List<CharacterName>(),
RealmName = characterName.RealmName
};
db.GuildName.Add(guildName);
}
Related
I'm implementing asp.net core project. In my controller class, create method, At first I insert a record in table APIApplicantHistory as a log history and then I do some calculation to get a value and after that I return back to the create method and and create a new record and insert it into APIApplicant table. For doing that, I wrote some code like below:
namespace CSDDashboard.Controllers
{
public class ApiapplicantsController : Controller
{
private readonly CSSDDashboardContext _context;
public ApiapplicantsController(CSSDDashboardContext context)
{
_context = context;
}
public async Task<IActionResult> Create([Bind("Id,ApiRequestDate,ApiRequestNo,Apiid,ApplicantId,GateId,LastRequestStatus,NocRequestDate,NocRequestNo,Url,Description,IsDeleted")] Apiapplicant apiapplicant)
{
ApiApplicantDto dto = new ApiApplicantDto();
if (ModelState.IsValid)
{
// Apiapplicant myapiapplicant = _context.Apiapplicant.LastOrDefault<Apiapplicant>();
Apiapplicant myapiapplicant = _context.Apiapplicant.ToArray().Last();
int temp = myapiapplicant.Id + 1;
int calcApiApplicantHistoryId = APIApplicantHistoryLog(temp);
var api = _context.Api.Single(p => p.Id == apiapplicant.Apiid);
var gate = _context.Gate.Single(p => p.Id == apiapplicant.GateId);
var applicant = _context.Applicant.Single(p => p.ApplicantId == apiapplicant.ApplicantId);
//var apiapplicanthistory = _context.ApiApplicantHistory.Single(p => p.Id == apiapplicant.LastRequestStatus);
dto.apiId = api.Id;
dto.gateId = gate.Id;
dto.applicantId = applicant.ApplicantId;
using (var _context = new CSSDDashboardContext())
{
_context.Set<Apiapplicant>().Add(new Apiapplicant
{
Apiid = dto.apiId,
GateId = dto.gateId,
ApplicantId = dto.applicantId,
LastRequestStatus = calcApiApplicantHistoryId,
ApiRequestDate = apiapplicant.ApiRequestDate,
ApiRequestNo = apiapplicant.ApiRequestNo,
NocRequestDate = apiapplicant.NocRequestDate,
NocRequestNo = apiapplicant.NocRequestNo,
Url = apiapplicant.Url,
Description = apiapplicant.Description,
IsDeleted = false
});
await _context.SaveChangesAsync();
};
return RedirectToAction(nameof(Index));
}
ViewData["Apiid"] = new SelectList(_context.Api, "Id", "Name", apiapplicant.Apiid);
ViewData["ApplicantId"] = new SelectList(_context.Applicant, "ApplicantId", "Name", apiapplicant.ApplicantId);
ViewData["GateId"] = new SelectList(_context.Gate, "Id", "Name", apiapplicant.GateId);
ViewData["sentResponseType"] = new SelectList(_context.EntityType.Where(g => g.EntityKey=="sentResponseType").ToList(), "ID", "name", apiapplicant.LastRequestStatusNavigation.SentResponseType);
ViewData["unconfirmedReason"] = new SelectList(_context.EntityType.Where(g => g.EntityKey == "unconfirmedReason").ToList(), "Id", "name", apiapplicant.LastRequestStatusNavigation.UnconfirmedReason);
ViewData["lastReqStatus"] = new SelectList(_context.EntityType.Where(g => g.EntityKey == "lastRequestStatus").ToList(), "Id", "name", apiapplicant.LastRequestStatusNavigation.LastReqStatus);
return View(apiapplicant);
}
private int APIApplicantHistoryLog(int myAPIApplicantId)
{
APIApplicantHistoryDto mydto = new APIApplicantHistoryDto();
// var apiapplicantt = _context.ApiApplicantHistory.Single(p => p.ApiApplicantId == myAPIApplicantId);
// mydto.APIApplicantHistoryId = apiapplicantt.Id;
using (var _context = new CSSDDashboardContext())
// using (var transaction = _context.Database.BeginTransaction())
{
_context.Set<ApiApplicantHistory>().Add(new ApiApplicantHistory
{
// ApiApplicantId = mydto.APIApplicantHistoryId,
ApiApplicantId = myAPIApplicantId,
Date = null,
SentResponseType = 0,
UnconfirmedReason = 0,
LastReqStatus = 0,
Description = "",
IdDeleted = false // This field should be totally omited from SQL server
}) ;
_context.SaveChangesAsync();
var myArrayList = new List<int>();
var result = from x in _context.ApiApplicantHistory where x.ApiApplicantId == myAPIApplicantId
select new { x.Id };
foreach (var i in result)
myArrayList.Add(i.Id);
return myArrayList.Max(); ;
}
}
}
My problem is, after running the application and create a new record in APIApplicant, the below error is shown to me:
An unhandled exception occurred while processing the request.
InvalidOperationException: A second operation started on this context
before a previous operation completed. This is usually caused by
different threads using the same instance of DbContext. For more
information on how to avoid threading issues with DbContext, see
https://go.microsoft.com/fwlink/?linkid=2097913.
I appreciate if any one tells me where do I make a mistake?
If you click on the link from the exception message: https://go.microsoft.com/fwlink/?linkid=2097913 it seems straight forward:
Entity Framework Core does not support multiple parallel operations
being run on the same DbContext instance. This includes both parallel
execution of async queries and any explicit concurrent use from
multiple threads. Therefore, always await async calls immediately, or
use separate DbContext instances for operations that execute in
parallel.
If you check your APIApplicantHistoryLog method you are not awaiting your _context.SaveChangesAsync(); method call.
I'm working on ASP.NET Boilerplate. I have the problem where I try to get a record from a table called Buildings and make an update on it. I get the record from database by:
var buildingApp = _buildingsAppService.getBuildingsById(buildingInput);
And after that, I make some changes on the data as follows:
buildingApp.streetName = Request["buildingaddress"];
buildingApp.isInHoush = Convert.ToBoolean(Request["buildingOutput.isInHoush"]);
buildingApp.houshName = Request["HoushName"];
And then copy the buildingApp to another object, which has the same properties, in order to pass the new object to update method as follows:
var updateBuildingInput = new UpdateBuidlingsInput()
{
Id = buildingApp.Id,
buildingID = buildingApp.buildingID,
numOfBuildingUnits = buildingApp.numOfBuildingUnits,
numOfFloors = buildingApp.numOfFloors,
streetName = buildingApp.streetName,
buildingNo = buildingApp.buildingNo,
neighborhoodID = buildingApp.neighborhoodID,
buildingTypeID = buildingApp.buildingTypeID,
GISMAP = buildingApp.GISMAP,
houshProperty = buildingApp.houshProperty,
houshName = buildingApp.houshName,
X = buildingApp.X,
Y = buildingApp.Y,
buildingName = buildingApp.buildingName,
isInHoush = buildingApp.isInHoush,
buildingUsesID = buildingApp.buildingUsesID
};
And the update method is as follows:
_buildingsAppService.update(updateBuildingInput);
The problem is when it executes the previous line, I get the following error:
System.InvalidOperationException: 'Attaching an entity of type 'TaawonMVC.Models.Buildings' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.'
I can see that when I initialize the object updateBuildingInput manually, the update method runs without error. But when it depends on the object obtained from database using buildingApp, the error happens. It seems like the get method gets data from database and keeps holding on to the record from database, and when I try to update the same record, the conflict happens. This is the whole action where all of get and update happens:
public ActionResult UpdateApplication (UpdateApplicationsInput model)
{
var updateApplication = new UpdateApplicationsInput();
updateApplication.buildingId = Convert.ToInt32(Request["buildingnumber"]);
updateApplication.buildingUnitId = Convert.ToInt32(Request["dropDownBuildingUnitApp"]);
//==== get building and unit related to application for update ======
var buildingInput = new GetBuidlingsInput()
{
Id = updateApplication.buildingId
};
var buildingUnitInput = new GetBuildingUnitsInput()
{
Id = updateApplication.buildingUnitId
};
var buildingApp = _buildingsAppService.getBuildingsById(buildingInput);
var buildingUnitApp = _buildingUnitsAppService.GetBuildingUnitsById(buildingUnitInput);
buildingApp.streetName = Request["buildingaddress"];
buildingApp.isInHoush = Convert.ToBoolean(Request["buildingOutput.isInHoush"]);
buildingApp.houshName = Request["HoushName"];
// buildingUnitApp.BuildingId = updateApplication.buildingId;
buildingUnitApp.ResidenceStatus = Request["residentstatus"];
// copy object getBuildingUnitInput to updateBuildingUnitInput
var updateBuildingUnitInput = new UpdateBuildingUnitsInput()
{
BuildingId = buildingUnitApp.BuildingId,
ResidentName = buildingUnitApp.ResidentName,
ResidenceStatus = buildingUnitApp.ResidenceStatus,
NumberOfFamilyMembers = buildingUnitApp.NumberOfFamilyMembers,
Floor = buildingUnitApp.Floor,
UnitContentsIds = buildingUnitApp.UnitContentsIds
};
//============================================
// copy object from getBuildingOutput to updateBuildingInput
var updateBuildingInput = new UpdateBuidlingsInput()
{
Id = buildingApp.Id,
buildingID = buildingApp.buildingID,
numOfBuildingUnits = buildingApp.numOfBuildingUnits,
numOfFloors = buildingApp.numOfFloors,
streetName = buildingApp.streetName,
buildingNo = buildingApp.buildingNo,
neighborhoodID = buildingApp.neighborhoodID,
buildingTypeID = buildingApp.buildingTypeID,
GISMAP = buildingApp.GISMAP,
houshProperty = buildingApp.houshProperty,
houshName = buildingApp.houshName,
X = buildingApp.X,
Y = buildingApp.Y,
buildingName = buildingApp.buildingName,
isInHoush = buildingApp.isInHoush,
buildingUsesID = buildingApp.buildingUsesID
};
//======================================================
updateApplication.Id = Convert.ToInt32(Request["applicationId"]);
updateApplication.fullName = model.fullName;
updateApplication.phoneNumber1 = model.phoneNumber1;
updateApplication.phoneNumber2 = model.phoneNumber2;
updateApplication.isThereFundingOrPreviousRestoration = model.isThereFundingOrPreviousRestoration;
updateApplication.isThereInterestedRepairingEntity = model.isThereInterestedRepairingEntity;
updateApplication.housingSince = model.housingSince;
updateApplication.previousRestorationSource = model.previousRestorationSource;
updateApplication.interestedRepairingEntityName = model.interestedRepairingEntityName;
updateApplication.PropertyOwnerShipId = Convert.ToInt32(Request["PropertyOwnerShip"]);
updateApplication.otherOwnershipType = model.otherOwnershipType;
updateApplication.interventionTypeId = Convert.ToInt32(Request["interventionTypeName"]);
updateApplication.otherRestorationType = model.otherRestorationType;
updateApplication.propertyStatusDescription = model.propertyStatusDescription;
updateApplication.requiredRestoration = model.requiredRestoration;
updateApplication.buildingId = Convert.ToInt32(Request["buildingnumber"]);
updateApplication.buildingUnitId = Convert.ToInt32(Request["dropDownBuildingUnitApp"]);
// ==== get of restoration types which it is multi select drop down list ======
var restorationTypes = Request["example-getting-started"];
string[] restorationTypesSplited = restorationTypes.Split(',');
byte[] restorationTypesArray = new byte[restorationTypesSplited.Length];
for (var i = 0; i < restorationTypesArray.Length; i++)
{
restorationTypesArray[i] = Convert.ToByte(restorationTypesSplited[i]);
}
updateApplication.restorationTypeIds = restorationTypesArray;
// ====== end of RestorationTypes
_buildingsAppService.update(updateBuildingInput);
_applicationsAppService.Update(updateApplication);
// _buildingUnitsAppService.Update(updateBuildingUnitInput);
// ==== get list of applications ==============
var applicationsUpdate = _applicationsAppService.getAllApplications();
var applicationsViewModel = new ApplicationsViewModel()
{
Applications = applicationsUpdate
};
return View("Applications", applicationsViewModel);
}
How ASP.NET Boilerplate template, which I use, makes CRUD Operation to database:
public class BuildingsManager : DomainService, IBuildingsManager
{
private readonly IRepository<Buildings> _repositoryBuildings;
public BuildingsManager(IRepository<Buildings> repositoryBuildings)
{
_repositoryBuildings = repositoryBuildings;
}
// create new building in table buildings .
public async Task<Buildings> create(Buildings entity)
{
var building = _repositoryBuildings.FirstOrDefault(x => x.Id == entity.Id);
if(building!=null)
{
throw new UserFriendlyException("Building is already exist");
}
else
{
return await _repositoryBuildings.InsertAsync(entity);
}
}
// delete a building from buildings table .
public void delete(int id)
{
try
{
var building = _repositoryBuildings.Get(id);
_repositoryBuildings.Delete(building);
}
catch (Exception)
{
throw new UserFriendlyException("Building is not exist");
}
}
public IEnumerable<Buildings> getAllList()
{
return _repositoryBuildings.GetAllIncluding(b => b.BuildingType, n => n.NeighboorHood,u=>u.BuildingUses);
}
public Buildings getBuildingsById(int id)
{
return _repositoryBuildings.Get(id);
}
public void update(Buildings entity)
{
_repositoryBuildings.Update(entity);
}
}
How can I solve this problem? Many thanks for help.
By creating a new entity (updateBuildingInput) with the same primary key as one you have already read in your context, Entity will throw an error when you attempt an operation on the new entity (as you have seen) as it is already tracking an entity with that primary key in the context.
If _buildingsAppService is a DbContext and all you need to do is make some changes to an entity, you can:
Read the entity
Make changes directly to that entity object
Call _buildingsAppService.SaveChanges()
SaveChanges() will:
Saves all changes made in this context to the underlying database.
When getting the record from db you can use .AsNoTracking()
Or if you really need to update an attached entity first locate the attached copy and detach it, then modify and update;
public async Task<bool> UpdateAsync<T>(T entity)
where T : class, IHasId
{
// check if entity is being tracked
var local = _context.Set<T>().Local.FirstOrDefault(x => x.Id.Equals(entity.Id));
// if entity is tracked detach it from context
if (local != null)
_context.Entry<T>(local).State = EntityState.Detached;
_context.Attach(entity).State = EntityState.Modified;
var result = await _context.SaveChangesAsync();
// detach entity if it was not tracked, otherwise it will be kept tracking
if(local == null)
_context.Entry(entity).State = EntityState.Detached;
return result > 0;
}
btw, IHasId is a simple interface to make Id property accessible for generic types;
public interface IHasId {
int Id { get; set; }
}
Use .AsNoTracking():
public class BuildingsManager : DomainService, IBuildingsManager
{
public Buildings getBuildingsById(int id)
{
return _repositoryBuildings.GetAll().AsNoTracking().First(b => b.Id == id);
}
// ...
}
I pull student data from 2 databases. 1 from an online SOAP API which can handle async calls and 1 from a local DB with an older services that doesnt support async.
I compare these databases and write the differences in a local sqlDB through EF.
Problem:
I get double entries in my EF DB. He puts the correct data and amount in arrays inside the method, but it looks like once he hits the db.savechanges() he jumps back up a few line and saves again.
I don't even know where this extra thread comes from.
Some code might be still there from numerous tries to solve it. For instance I tried with addrange but I get an error when he tries to add the FullVarianceList.
public async Task<bool> FullStudentCompare(string date) //format DD/MM/YYYY
{
try
{
//DB context
using (var db = new SchoolDbContext())
{
//GET DATA
//SMT (async)
List<SmtStudent> smtStdudentList = await GetAllSmartschoolStudents();
//Wisa (sync)
//on date, or if emty on current systemdate
List<WisaStudent> wisaList;
if (date == "")
{
wisaList = GetWisaStudentData(DateTime.Now.ToShortDateString());
}
else
{
wisaList = GetWisaStudentData(date);
}
//Flags and props needed for DB entry after compare
bool existsInLocalDb = false;
List<Variance> vList = new List<Variance>();
//Full list to add to DB outside foreach
List<Variance> fullVarianceList = new List<Variance>();
//Full List of new Students to write to DB outside foreach
List<DbStudent> fullStudentList = new List<DbStudent>();
//Compare lists
foreach (WisaStudent wstd in wisaList)
{
//determine correct classCode
string klasCode;
if (wstd.klasgroep.Trim() == "Klasgroep 00")
{
klasCode = wstd.klas.Trim();
}
else
{
klasCode = wstd.klasgroep.Trim();
}
//Create SmtStudent object for compare
SmtStudent tempStd = new SmtStudent(true,
wstd.voornaam.Trim(),
wstd.naam.Trim(),
wstd.stamboeknummer.Trim(),
wstd.geslacht.Trim(),
wstd.geboortedatum.Trim(),
wstd.straat.Trim(),
wstd.huisnummer.Trim(),
wstd.busnummer.Trim(),
wstd.postcode.Trim(),
wstd.gemeente.Trim(),
wstd.emailadres.Trim(),
wstd.GSM_nummer.Trim(),
wstd.levensbeschouwing.Trim(),
wstd.coaccountmoedervoornaam.Trim(),
wstd.coaccountmoedernaam.Trim(),
wstd.coaccountmoederemailadres.Trim(),
wstd.coaccountmoederGSM_nummer.Trim(),
wstd.coaccountvadervoornaam.Trim(),
wstd.coaccountvadernaam.Trim(),
wstd.coaccountvaderemailadres.Trim(),
wstd.coaccountvaderGSM_nummer.Trim(),
klasCode,
wstd.nationaliteit,
wstd.geboorteGemeente,
wstd.geboorteLand
);
//Find matching SmtStudent
SmtStudent smtStd = smtStdudentList.Find(i => i.Internnummer == wstd.stamboeknummer);
//Find matching Std in local DB
DbStudent dbStd = await db.Students.Where(i => i.Stamboeknummer == wstd.stamboeknummer).FirstOrDefaultAsync();
//if none exists in the local DB create an entity to update and write to DB
if (dbStd == null)
{
dbStd = new DbStudent(wstd.voornaam.Trim(),
wstd.naam.Trim(),
wstd.stamboeknummer.Trim(),
wstd.geslacht.Trim(),
wstd.geboortedatum.Trim(),
wstd.straat.Trim(),
wstd.huisnummer.Trim(),
wstd.busnummer.Trim(),
wstd.postcode.Trim(),
wstd.gemeente.Trim(),
wstd.emailadres.Trim(),
wstd.GSM_nummer.Trim(),
wstd.levensbeschouwing.Trim(),
wstd.coaccountmoedervoornaam.Trim(),
wstd.coaccountmoedernaam.Trim(),
wstd.coaccountmoederemailadres.Trim(),
wstd.coaccountmoederGSM_nummer.Trim(),
wstd.coaccountvadervoornaam.Trim(),
wstd.coaccountvadernaam.Trim(),
wstd.coaccountvaderemailadres.Trim(),
wstd.coaccountvaderGSM_nummer.Trim(),
klasCode,
wstd.loopbaanDatum,
wstd.nationaliteit,
wstd.geboorteGemeente,
wstd.geboorteLand
);
db.Students.Add(dbStd);
fullStudentList.Add(dbStd);
}
else
{
existsInLocalDb = true;
}
if (smtStd == null)
{
//Std doesn't exist in Smt -> New student
dbStd.IsNewStudent = true;
dbStd.ClassMovement = true;
//remove from wisaList
wisaList.Remove(wstd);
}
else
{
//clear vlist from previous iterations
vList.Clear();
//get all properties on the obj, cycle through them and find differences
PropertyInfo[] props = smtStd.GetType().GetProperties();
vList.AddRange(props.Select(f => new Variance
{
Property = f.Name,
ValueA = f.GetValue(smtStd),
ValueB = f.GetValue(tempStd),
Checked = false
})
.Where(v => !v.ValueA.Equals(v.ValueB) && v.ValueB != null)
.ToList());
//If the users allrdy exists in LocalDb delete all previously recorded variances
if (existsInLocalDb)
{
if (db.Variances.Where(j => j.Student.StudentId.Equals(dbStd.StudentId)).FirstOrDefault() != null)
{ //if the student allready exists we will recreate the variancelist, hence deleting all current items first
List<Variance> existingList = db.Variances.Where(j => j.Student.StudentId.Equals(dbStd.StudentId)).ToList();
foreach (Variance v in existingList)
{
db.Variances.Remove(v);
}
}
}
//Add new variances if vList is not empty
if (vList.Count > 0)
{
//Check if KlasCode is a variance -> set classmovement to true
if (vList.Where(i => i.Property == "KlasCode").FirstOrDefault() != null)
{
dbStd.ClassMovement = true;
}
else
{
dbStd.ClassMovement = false;
}
//add the StudentObject to the variance to link them 1-many
foreach (Variance v in vList)
{
v.Student = dbStd;
fullVarianceList.Add(v);
db.Variances.Add(v);
}
}
}
}
//add the full lists of variances and new students to DB
//db.Variances.AddRange(fullVarianceList);
//db.Students.AddRange(fullStudentList);
db.SaveChanges();
return true;
}
}
catch(Exception ex)
{
return false;
}
}
A couple of things:
It is important to understand that EF uses a unit of work pattern where none of the changes to the entities are persisted until SaveChanges is called which explains the "once he hits the db.Savechanges() he jumps back up" phenomenon.
When you have a 1 to many relationsship and you assign a collection of entities to a navigation property on another entity and then add that parent entity to the DbContext, EF marks those child entities to be added too. In your case dbStd is added at the line "db.Students.Add(dbStd);" and at the line "v.Student = dbStd;". This is most likely what is causing your duplicates.
I am using a WCF refrence to call the last row from my Quote table. Now I wrote this method in my WCF application to get the last row, but I do not know it it works or not(I am trying to test it):
public void GetLastQuote()
{
using (TruckDb db = new TruckDb())
{
var quote = (from qData in db.Quotes
where qData.Id == qData.RepresetativeId
orderby qData.Id descending
select qData).First();
}
}
In my WPF application I am using the WCF reference and calling on the GetLastQuoteAsync() method, but it is giving me the following error:
Cannot assign void to an implicitly-typed local variable
And here is the method in my WPF application where I am trying to call the GetLastQuoteAsync() reference.
private async void wListOfBills_Loaded(object sender, RoutedEventArgs e)
{
using (TruckServiceClient client = new TruckServiceClient())
{
var quote = await client.GetLastQuoteAsync(); // -> This is where the error lies.
var bills = await client.GetListOfBillsAsync(quote.Item.Id);
if (bills == null)
{
dgFloor.IsEnabled = true;
return;
}
dgFloor.ItemsSource = bills.Select(x => new ListOfBillsView
{
Code = x.StockCode,
Group = x.GroupName,
Description = x.StockDescription,
Qty = x.Quantity,
Length = x.Length,
Width = x.Width,
Weight = x.Weight,
Price_m = x.PricePerMeter,
Cost = x.Cost,
Section = x.TruckSection.ToString()
}).ToList();
}
}
I have seen some people with the same question, but I do not fully understand how to implement the solutions in my own problem. If anyone could help, I would appreciate it allot! :)
You want to call what your query is returning, but the method wrapping around that query is returning nothing, because its type is void.
I assume you want to return an object of type Quote, so you need to change your method to this:
//change from void to Quote
public Quote GetLastQuote()
{
using (TruckDb db = new TruckDb())
{
var quote = (from qData in db.Quotes
where qData.Id == qData.RepresetativeId
orderby qData.Id descending
select qData).First();
//new
return quote;
}
}
Also GetLastQuote() is not the same as GetLastQuoteAsync() Have you posted the wrong method, which would throw the same error?
If there is also async version of this method it should probably look similar to this:
public async Task<Quote> GetLastQuote()
{
using (TruckDb db = new TruckDb())
{
var quote = (from qData in db.Quotes
where qData.Id == qData.RepresetativeId
orderby qData.Id descending
select qData).FirstAsync(); /*Note async method here*/
//new
return await quote;
}
}
i have some code that sets user's properties like so:
us = new UserSession();
us.EmailAddr = emailAddr;
us.FullName = fullName;
us.UserROB = GetUserROB(uprUserName);
us.UserID = GetUserID(uprUserName);
us.UserActive = GetUserActive(uprUserName);
where GetUserROB, GetUserID and GetUserActive all look similar like so:
private static string GetUserActive(string userName)
{
using (Entities ctx = CommonSERT.GetContext())
{
var result = (from ur in ctx.datUserRoles
where ur.AccountName.Equals(userName, StringComparison.CurrentCultureIgnoreCase)
select new
{
Active = ur.active
}).FirstOrDefault();
if (result != null)
return result.Active;
else
return "N";
}
}
it works, but i dont think it's the right way here. how can i assign userROB, ID and Active properties all in one LINQ call? without having to have 3 separate functions to do this?
If I understand correctly I believe you can do something like:
private static void GetUserData(string userName, UserSession userSession)
{
using (Entities ctx = CommonSERT.GetContext())
{
var result = (from ur in ctx.datUserRoles
where ur.AccountName.Equals(userName, StringComparison.CurrentCultureIgnoreCase)
select new
{
UserActive = ur.active,
UserROB = ur.ROB,
UserID = ur.ID
}).FirstOrDefault();
}
if (result != null) {
userSession.UserActive = result.UserActive;
userSession.UserROB = result.UserROB;
userSession.UserID = result.UserID;
}
}
In the select new you can place as many properties as you want, this way you can get from the database several properties in a single roundtrip, and handling it later.
In the example I gave, I pass the UserSession as a parameter, in any case you already have other properites alrealdy filled from other methods.
You can create a method that accepts a UserSession object as parameter, then set all three properties in it. I changed your GetUserActive a bit here:
private static void GetUserData(string userName, UserSession user)
{
using (Entities ctx = CommonSERT.GetContext())
{
var result = (from ur in ctx.datUserRoles
where ur.AccountName.Equals(userName, StringComparison.CurrentCultureIgnoreCase)
select new
{
Active = ur.active,
ID = ur.ID,
//...select all properties from the DB
}).FirstOrDefault();
if (result != null)
user.UserActive = result.Active;
user.UserID = result.ID;
//..set all properties of "user" object
}
}
Well you might consider normalising your domain model and having a User property of type User, then your method would return all of the related user data.