I'm new to LINQ and Entity Framework and would appreciate some advice on the following scenario.
I have a entity model with two tables.
Travel_Request and Resource
Sample Fields
Travel_Request
Request_ID
Resource_ID
Resource
Resource_ID
Resource_Name
I would like to add the Resource_Name to the list when returning all the TRAVEL_REQUESTS
Thanks in advance
Hi you need to use the Linq join:
var data = from t in Travel_Request
join r in Resource on t.Resource_ID equals r.Resource_ID
select new
{
RequestId = t.Request_ID,
ResourceId = t.Resource_ID,
ResourceName = r.Resource_Name
};
If you already have an EF association then it could simply be:
var data = from t in Travel_Request
select new
{
RequestId = t.Request_ID,
ResourceId = t.Resource_ID,
ResourceName = t.Resource.Resource_Name
};
You will have to create a new object something like this.
var data = Travel_Request.Select(s=> new { Resource_Name = s.Recource.Resource_Name, Request_ID = s.Request_ID, Resource_ID = s.Resource_ID}).ToList();
As long as I've understood the question correctly this will work.
You can query Travel_Request entity and use the navigation propety to do that.
var resultList = DbContext.Travel_Request.Resources.where(x=>x.Resource_Name =="Your string").ToList();
I would add a model that has all three then do something like.
var TravelRequests =
from p in Travel_Request
from r in Resource.where(Res => Res.Resource_ID == p.Resource_ID)
select new TravelModel{
requestID = p.requestID,
Resource_ID = p.Resource_ID,
ResourceName = r.ResourceName
};
But thats just an example of how I would do it and there might be better ways. Also syntax might be a little off but general idea is there.
Use the Join:
Travel_Request.Join(Resource, tr => tr.ResourceId, r => r.ResourceId, (tr, r) => new { RequestId = tr.RequestId, ResourceId = tr.ResourceId, Name = r.ResourceName})
Or what a better practice would be is adding a Navigation property to TravelRequest.
TravelRequest would look like this:
int RequestId { get; set; }
int ResourceId{ get; set; }
[ForeignKey("ResourceId")]
Resource Resource { get; set; }
This way you can use Include
DBContext.TravelRequests.Include("Resource").First().Resource.Name;
Include tells EF to get the Resource with the TravelerRequest
Related
I am getting MongoDb.Bson.SerializationException: 'Element name '_t' is not valid.
I read all posts online that appear to be similar issue at first, however, in those posts, element name is specified, here, i am only getting '_t' even by trying different class objects.
var database = AppConfig.client.GetDatabase("test");
var collection = database.GetCollection<BsonDocument>("testcollection");
var filter = Builders<Student>.Filter.Eq(g => g.Name, "oldName");
var update = Builders<Student>.Update.Set(g => g.Name, "NewName");
var updateResult = await collection.UpdateOneAsync(filter.ToBsonDocument(), update.ToBsonDocument());
Also, for all examples i have seen online for UpdateOneAsync function, filter and update below do NOT need to be BSON documents, however, my code won't compile unless I do .ToBSONDocument() as above.
var updateResult = await collection.UpdateOneAsync(filter, update);
My class is minimal:
public class Student
{
[BsonElement("Name")]
public string Name { get; set; }
[BsonElement("Age")]
public int Age { get; set; }
}
Can someone please help figure out what is wrong with above?
Update: How to use render for Update.Set
var registry = BsonSerializer.SerializerRegistry;
var serializer = registry.GetSerializer<Student>();
var filter = Builders<Student>.Filter.Eq(g=> g.Name, "NewName").Render(serializer, registry);
//I think update syntax is not correct.
var update = Builders<Student>.Update.Set(g => g.Name, "Changed").Render(serializer, registry);
//update is throwing error:cannot convert from Mongodb.bson.bsonvalue to mongodb.Driver.updatedefinition<MongoDB.Bson.BsonDocument
var updateResult = await collection.UpdateOneAsync(filter, update);
it's impossible to use ToBsonDocument as you did. The easiest fix is using not typed builders:
var filter = Builders<BsonDocument>.Filter.Eq("name", "oldName");
If you want to use typed builder, you should call Render as below:
var registry = BsonSerializer.SerializerRegistry;
var serializer = registry.GetSerializer<Student>();
var filter = Builders<Student>.Filter.Eq(e=>e.Name, "oldName").Render(serializer, registry);
I am creating stored procedures in SQL Server database and have been having issues returning the data when called.
I have managed to get it to work, but it feels as if it is a hack job and that I am doing it incorrectly. Please see the code below and let me know if there is a better way to go about doing this. Thank you for taking the time to help me.
create procedure FetchSumOfEmpSalariesByCity
as
begin
select
sum(e.SAL) as TotalSalary, d.LOC as Location
from
EMPS e
join
DEPTs d on e.DEPTNO = d.DEPTNO
group by
d.LOC
end
public class SumOfEmpsSalaryByCity
{
[Key]
public int TotalSalary { get; set; }
public string Location { get; set; }
}
[HttpGet]
[Route("salary")]
public IHttpActionResult GetEMPsSal()
{
using (var db = new KemmitContext())
{
var sp = db.SumOfEmpsSalaryByCities.SqlQuery("FetchSumOfEmpSalariesByCity");
return Ok(sp.ToList());
}
}
I want to do this the correct way. Is there a way to do this without a model? Or am I going about this the right way?
I break these tasks down like this; should it be done with EF or in the database and if it's in the database, should it be a View or an Sp?
Whenever I'm simply selecting data, I use EF either direct to the table for very simple queries or I create a database View for any joins, etc. This can be done in EF but it's god-awful, in any case, IMO these tasks belong in the database, right tool, right job. If you're using code-first, getting your Views across is a bit involved, let me know if you're doing that.
var model = db.v_ObservationAutoComplete // This can be direct to a table or a view
.Where(oa => oa.Observation.Contains(term))
.OrderBy(oa => oa.Observation)
.Select(oa => new
{
label = oa.Observation
}).Take(10);
When I have to update something in a single table, I use EF
t_Section eSection = new t_Section
{
SectionId = model.SectionId,
Section = model.Section,
SectionTypeId = model.SectionTypeId,
SectionOrdinal = model.SectionOrdinal,
ModifyDate = DateTime.Now,
ModifyUserName = User.Identity.Name,
LastChangeId = newChangeId
};
db.Entry(eSection).State = EntityState.Modified;
db.SaveChanges();
If I have to do a multi-table update, I have a couple of different methodologies; 1) returning a simple bool value for a status code/scalar value, or I have to return a result set after doing whatever update I made.
This returns a List
List<string> elements = new List<string>();
try
{
SqlParameter[] parms = new[]
{
new SqlParameter("mpid", myProtocolsId),
new SqlParameter("elid", elementId)
};
elements = db.Database.SqlQuery<string>("p_MyProtocolsOverviewElementRemove #myProtocolsId = #mpid, #elementId = #elid", parms).ToList();
return Json(elements);
}
catch (Exception e)
{
return Json(null);
}
And if I just need a simple value back, something like this;
SqlParameter[] parms = new[]
{
new SqlParameter("chid", changeId),
new SqlParameter("prid", change.ObjectId),
new SqlParameter("psid", change.ProtocolSectionId),
new SqlParameter("inid", change.SecondaryObjectId),
new SqlParameter("acun", User.Identity.Name)
};
result = db.Database.SqlQuery<int>("p_MyProtocolsContentUpdateInterventionAdd #changeId = #chid, #protocolId = #prid, #protocolSectionId = #psid, #interventionId = #inid, #acceptUserName = #acun", parms).FirstOrDefault();
Hope this helps!
I have been using AutoMapper which I find really good.
But in current project I can't use AutoMapper because few reasons. lets not go into that.
Wondering if below is best way of manual mapping? Seems like it will be lot of looping depending on complexity of the model and one to many relationship.
Is there best or efficient way of doing manual mapping.
Basket basket = StoreRepository.GetBasket(BasketCode); // where BasketCode is xyz
List<ProductResponse> basketProducts = new List<ProductResponse>();
foreach (Product product in basket.Products) {
basketProducts.Add(new ProductResponse()
{
Name = product.Name,
Description = product.Description
});
}
BasketResponse result = new BasketResponse()
{
BasketCode = basket.Code,
Description = basket.Description,
IntroMessage = basket.IntroMessage,
Products = basketProducts
};
return result;
Above is snippet from a method of Web API Controller which return Json.
I am using manual mapping to reduce detailed complexity and create required Json structure and data.
You would probably be better off creating some kind of general function for each class so you don't have to repeat the mapping everytime you want to use it. For example:
public static class Mapper
{
public static ProductResponse Map(Product product)
{
return new ProductResponse
{
Name = product.Name,
Description = product.Description
};
}
public static BasketResponse Map(Basket basket)
{
return new BasketResponse
{
BasketCode = basket.Code,
Description = basket.Description,
IntroMessage = basket.IntroMessage,
Products = basket.Products.Select(a => Mapper.Map(a))
};
}
}
May be this question should be in code review. Anyway you can simplify your code by using Select LINQ query instead of FOREACH loop to build basketProducts list, like below.
List<ProductResponse> basketProducts = basket.Products.Select(product=> new ProductResponse()
{
Name = product.Name,
Description = product.Description
}).ToList();
You can simplify this further by writing a new delegate for mapping which can be reused at multiple places.
Func<Product, ProductResponse> MapProduct = delegate (Product product)
{
return new ProductResponse()
{
Name = product.Name,
Description = product.Description
};
};
then your code will be much simpler like below. Use the new delegate in SELECT method of LINQ query.
Basket basket = StoreRepository.GetBasket(BasketCode);
BasketResponse result = new BasketResponse()
{
BasketCode = basket.Code,
Description = basket.Description,
IntroMessage = basket.IntroMessage,
Products = basket.Products.Select(MapProduct).ToList()
};
return result;
We have a settings file which is basically Xml that we are extending for pluggable modules we are writing. Basically we want to use our existing Xml settings but allow extension methods to be written on them. Long story short if we had an Xml file like so:
<Settings>
<SettingsOne Key1_1="Value1"
Key1_2="Value2" />
<SettingsTwo Key2_1="Value1"
Key2_2="Value2" />
</Settings>
How could we load this as an collection of SettingsEntry where SettingsEntry looked like so:
public class SettingsEntry
{
public string Section { get; set; }
public string Key { get; set; }
public string Value { get; set; }
}
Where Section would be "SettingsOne", Key would be "Key1_1" and Value would be "Value1".
Is this even possible or am I going down a dark path?
EDIT:
OK the suggestion of Linq to Xml was a life save, I was trying to do this with XmlSerializer! Below is what I have so far, is there a way to turn this into a single select rather than two like I have below:
var root = XElement.Load(pathToXml);
var sections = from el in root.Elements()
select el.Name;
List<SettingsEntry> settings = new List<SettingsEntry>();
foreach (var item in sections)
{
var attributes = from el in root.Elements(item).Attributes()
select new SettingsEntry()
{
Section = item.LocalName,
Key = el.Name.LocalName,
Value = el.Value
};
settings.AddRange(attributes);
}
return settings;
EDIT 2:
This seems to work.
var sections = from el in root.Elements()
from a in root.Elements(el.Name).Attributes()
select new SettingsEntry()
{
Section = el.Name.LocalName,
Key = a.Name.LocalName,
Value = a.Value
};
You can do that in one LINQ query like this :
var attributes = from attribute in root.Elements().Attributes()
select new SettingsEntry()
{
Section = attribute.Parent.Name.LocalName,
Key = attribute.Name.LocalName,
Value = attribute.Value
};
return attributes.ToList();
var xml = #"
<Settings>
<SettingsOne Key1_1= ""Value1"" Key1_2= ""Value1""></SettingsOne>
<SettingsTwo Key2_1= ""Value1"" Key2_2= ""Value1""></SettingsTwo>
</Settings>"
var root = XDocument.Parse(xml);
var q = root.Elements("Settings").Descendants();
List<SettingsEntry> settings = (from el in root.Elements("Settings").Descendants()
select new SettingsEntry()
{
Section = el.Name.ToString(),
Key = el.FirstAttribute.Value,
Value = el.LastAttribute.Value
}).ToList();
You might have to play with it a little to get the exact Object you want, but this is a serious push in the right direction.
I have a many to many relationship between Contractors and SafetyCouncils. They are joined by a bridge table ContractorsSafetyCouncils which consists of ContractorId and SafetyCouncilId. These 2 columns form a composite key. This relationship is mapped correctly in EF4. The Contractor entity has the property:
public virtual ICollection<SafetyCouncil> SafetyCouncils
{
get;
set;
}
And the SafetyCouncil entity has the property:
public virtual ICollection<Contractor> Contractors
{
get;
set;
}
When accessing these properties via lazy loading from a single Contractor or SafetyCouncil entity, they work exactly as expected. But when accessing this relationship in a query:
from c in ContractorRepository.All()
where c.PQFs.Count() > 0
let psmAudits = c.PQFs.SelectMany(pqf => pqf.Audits)
let psmAudit = psmAudits.FirstOrDefault(audit => audit.CompletedDate == psmAudits.Max(a => a.CompletedDate))
let scsAudits = c.PQFs.SelectMany(pqf => pqf.SCSAudits)
let scsAudit = scsAudits.FirstOrDefault(audit => audit.CompletedDate == scsAudits.Max(a => a.CompletedDate))
select new MasterListItem()
{
AdministratorNotes = c.AdminFlags.Where(f => f.IsActive && f.ForPQF).Select(f => f.Text),
CanViewInfo = false,
ContractorName = c.ContractorName,
ContractorId = c.Id,
ContractorTaxId = c.TaxId,
SafetyCouncilIds = c.SafetyCouncils.Select(sc => sc.Id),
PQFSubmitted = c.PQFs.Max(p => p.PQFInfo.SubmittedDate.Value),
PSMAuditId = psmAudit.Id,
PSMAuditComplete = psmAudit.CompletedDate,
PSMAuditStatus = psmAudit.Status.Description,
SCSAuditId = scsAudit.Id,
SCSAuditComplete = scsAudit.CompletedDate
};
The problem occurs with:
SafetyCouncilIds = c.SafetyCouncils.Select(sc => sc.Id),
For every record the SafetyCouncilIds collection has 0 members, when based on the data in the database every record should have at least 1 SafetyCouncilId associated with it.
If I run the same query, but project into an anonymous type instead of the MasterListItem type, it works correctly. Why can't I project this query into my custom type?
Update:
My MasterListItem POCO contained the following properties:
public string SafetyCouncilIdsString
{
get;
set;
}
public IEnumerable<int> SafetyCouncilIds
{
set
{
StringBuilder sb = new StringBuilder(",");
foreach (var id in value)
{
sb.Append(id);
sb.Append(",");
}
this.SafetyCouncilIdsString = sb.ToString();
}
}
The SafetyCouncilIds property was the cause of the problem. I changed this to an automatic property and built the string elsewhere and projecting onto the POCO worked like a charm.
public IEnumerable<int> SafetyCouncilIds
{
set
{
StringBuilder sb = new StringBuilder(",");
foreach (var id in value)
{
sb = sb.Append(id).Append(","); // <-- try this
// *or sb = sb.AppendFormat("{0},", id);*
}
this.SafetyCouncilIdsString = sb.ToString();
}
}
I have two suggestions:
Try to isolate the the problem by removing any extra parts of the query.
Compare the two sql queries generated and find the differences.
Unfortunately, without access to your code or schema, I can't provide a better answer.
The SafetyCouncilIds property was the cause of the problem. I changed this to an automatic property and built the string elsewhere and projecting onto the POCO worked like a charm.