scope using a try catch and linq - c#

I really have tried with this but just can't quite get it to work.
I have a bunch of files that I am using Linq to parse, but some of them have a field that the others do not have. There is no way of knowing by the file name.
Here is the code that runs against the file:
var update = from d in document.Descendants("Update")
select new
{
OrderNumber = d.Element("OrderNumber").Value,
StopID = d.Element("StopID").Value,
TransmissionTime = d.Element("TransmissionTime").Value,
EventTime = d.Element("PODTime").Value,
recordCreated = d.Element("EventTime").Value,
EventType = d.Element("EventType").Value,
EventCode = d.Element("EventCode").Value,
POD = d.Element("POD").Value,
Note = d.Element("Note").Value,
CustomerID = d.Element("CustomerID").Value,
OrderID = d.Element("OrderID").Value,
StopRef = d.Element("StopRef").Value,
PieceCount = d.Element("PieceCount").Value,
TotalWeight = d.Element("TotalWeight").Value,
DriverID = d.Element("DriverID").Value
};
Now the problem is that some of them do not have the Element("PODTime") so I need a differnet linq query. I was just going to do a try/catch and if it fails run the other one (cludgy I know).
But obviously as soon as I put update in a try/catch I can no longer access it outside of it.
Normally I would just define it before the try/catch - but I can't get that to work here.
I have tried:
System.Linq.Enumerable update = new System.Linq.Enumerable();
But that is not right. If somebody could point me the right direction I would apprecaite it.
Solution:
Using Sledgehammers nudge combined with a Let:
var update = from d in document.Descendants("Update")
let elName = d.Element("PODTime")
select new
{
OrderNumber = d.Element("OrderNumber").Value,
StopID = d.Element("StopID").Value,
TransmissionTime = d.Element("TransmissionTime").Value,
EventTime = (elName != null) ? elName.Value : string.Empty,

You can use the new ?. operator for this:
d.Element("CustomerID")?.Value
Or if you can't use the newest C#, you can write a "Safe" method to wrap all your calls in:
string SafeGetValue(XElement elem)
{
if (elem == null)
return null;
return elem.Value;
}

Related

How to execute a stored procedure join without creating a new asp.net model?

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!

Sitefinity: Dynamic Content query optimization with field values

I will attempt to be as specific as possible. So we are using Sitefinity 8.1.5800, I have a couple dynamic content modules named ReleaseNotes and ReleaseNoteItems. ReleaseNotes has some fields but no reference to ReleaseNoteItems.
Release Note Items has fields and a related data field to ReleaseNotes.
So I can query all ReleaseNoteItems as dynamic content pretty quickly less than a second.
I then use these objects provided by sitefinity and map them to a C# object so I can use strong type. This mapping process is taking almost a minute and using over 600 queries for only 322 items (N+1).
In Short: I need to get all sitefinity objects and Map them to a usable c# object quicker than I currently am.
The method for fetching the dynamic content items (takes milliseconds):
private IList<DynamicContent> GetAllLiveReleaseNoteItemsByReleaseNoteParentId(Guid releaseNoteParentId)
{
DynamicModuleManager dynamicModuleManager = DynamicModuleManager.GetManager(String.Empty);
Type releasenoteitemType = TypeResolutionService.ResolveType("Telerik.Sitefinity.DynamicTypes.Model.ReleaseNoteItems.Releasenoteitem");
string releaseNoteParentTypeString = "Telerik.Sitefinity.DynamicTypes.Model.ReleaseNotes.Releasenote";
var provider = dynamicModuleManager.Provider as OpenAccessDynamicModuleProvider;
int? totalCount = 0;
var cultureName = "en";
Thread.CurrentThread.CurrentUICulture = new CultureInfo(cultureName);
Type releasenoteType = TypeResolutionService.ResolveType("Telerik.Sitefinity.DynamicTypes.Model.ReleaseNotes.Releasenote");
// This is how we get the releasenote items through filtering
DynamicContent myCurrentItem = dynamicModuleManager.GetDataItem(releasenoteType, releaseNoteParentId);
var myMasterParent =
dynamicModuleManager.Lifecycle.GetMaster(myCurrentItem) as DynamicContent;
var relatingItems = provider.GetRelatedItems(
releaseNoteParentTypeString,
"OpenAccessProvider",
myMasterParent.Id,
string.Empty,
releasenoteitemType,
ContentLifecycleStatus.Live,
string.Empty,
string.Empty,
null,
null,
ref totalCount,
RelationDirection.Parent).OfType<DynamicContent>();
IList<DynamicContent> allReleaseNoteItems = relatingItems.ToList();
return allReleaseNoteItems;
}
This is the method that takes almost a minute that is mapping sitefinity object to C# object:
public IList<ReleaseNoteItemModel> GetReleaseNoteItemsByReleaseNoteParent(ReleaseNoteModel releaseNoteItemParent)
{
return GetAllLiveReleaseNoteItemsByReleaseNoteParentId(releaseNoteItemParent.Id).Select(rn => new ReleaseNoteItemModel
{
Id = rn.Id,
Added = rn.GetValue("Added") is bool ? (bool)rn.GetValue("Added") : false,
BugId = rn.GetValue<string>("bug_id"),
BugStatus = rn.GetValue<Lstring>("bugStatus"),
Category = rn.GetValue<Lstring>("category"),
Component = rn.GetValue<Lstring>("component"),
#Content = rn.GetValue<Lstring>("content"),
Criticality = rn.GetValue<Lstring>("criticality"),
Customer = rn.GetValue<string>("customer"),
Date = rn.GetValue<DateTime?>("date"),
Grouped = rn.GetValue<string>("grouped"),
Override = rn.GetValue<string>("override"),
Patch_Num = rn.GetValue<string>("patch_num"),
PublishedDate = rn.PublicationDate,
Risk = rn.GetValue<Lstring>("risk"),
Title = rn.GetValue<string>("Title"),
Summary = rn.GetValue<Lstring>("summary"),
Prod_Name = rn.GetValue<Lstring>("prod_name"),
ReleaseNoteParent = releaseNoteItemParent,
McProductId = GetMcProductId(rn.GetRelatedItems("McProducts").Cast<DynamicContent>()),
}).ToList();
}
Is there any way to optimize this all into one query or a better way of doing this? Taking almost a minute to map this objects is too long for what we need to do with them.
If there is no way we will have to cache the items or make a SQL query. I would rather not do caching or SQL query if I do not have to.
Thank you in advance for any and all help you can provide, I am new to posting questions on stackoverflow so if you need any additional data please let me know.
Is there a reason why you are doing a .ToList() for the items? Is it possible for you to avoid that. In my opinion, most of the time(of the 1 minute) is taken to convert all your items into a list. Conversion from Sitefinity object to C# object is not the culprit here.
Look Arno's answer here: https://plus.google.com/u/0/112295105425490148444/posts/QrsVtxj1sCB?cfem=1
You can use the "Content links manager" to query dynamic modules relationships (both by parent -ParentItemId- or by child -ChildItemId-) much faster:
var providerName = String.Empty;
var parentTitle = "Parent";
var relatedTitle = "RelatedItem3";
DynamicModuleManager dynamicModuleManager = DynamicModuleManager.GetManager(providerName);
Type parentType = TypeResolutionService.ResolveType("Telerik.Sitefinity.DynamicTypes.Model.ParentModules.ParentModule");
Type relatedType = TypeResolutionService.ResolveType("Telerik.Sitefinity.DynamicTypes.Model.RelatedModules.RelatedModule");
ContentLinksManager contentLinksManager = ContentLinksManager.GetManager();
// get the live version of all parent items
var parentItems = dynamicModuleManager.GetDataItems(parentType).Where(i => i.GetValue<string>("Title").Contains(parentTitle) && i.Status == ContentLifecycleStatus.Live && i.Visible);
// get the ids of the related items.
// We use the OriginalContentId property since we work with the live vesrions of the dynamic modules
var parentItemIds = parentItems.Select(i => i.OriginalContentId).ToList();
// get the live versions of all the schedules items
var relatedItems = dynamicModuleManager.GetDataItems(relatedType).Where(i => i.Status == ContentLifecycleStatus.Live && i.Visible && i.GetValue<string>("Title").Contains(relatedTitle));
// get the content links
var contentLinks = contentLinksManager.GetContentLinks().Where(cl => cl.ParentItemType == parentType.FullName && cl.ComponentPropertyName == "RelatedField" && parentItemIds.Contains(cl.ParentItemId) && cl.AvailableForLive);
// get the IDs of the desired parent items
var filteredParentItemIds = contentLinks.Join<ContentLink, DynamicContent, Guid, Guid>(relatedItems, (cl) => cl.ChildItemId, (i) => i.OriginalContentId, (cl, i) => cl.ParentItemId).Distinct();
// get the desired parent items by the filtered IDs
var filteredParentItems = parentItems.Where(i => filteredParentItemIds.Contains(i.OriginalContentId)).ToList();
I would imagine that every release note item under a single release note would be related to the same product wouldn't it?
If so, do you need to do the GetMcProductId method for every item?

Include properties based on conditions in anonymous types

Supposing I have the following anonymous type
var g = records.Select(r => new
{
Id = r.CardholderNo,
TimeIn = r.ArriveTime,
TimeOut = r.LeaveTime,
});
Is it possible to do something like the following:
var g = records.Select(r => new
{
Id = r.CardholderNo,
if (condition)
{
TimeIn = r.ArriveTime;
},
TimeOut = r.LeaveTime,
//many more properties that I'd like to be dependant on conditions.
});
How can I achieve an anonymous type based on conditions?
You can do this by using the ternary operator: ?:
The syntax is like this:
TimeIn = condition ? r.ArriveTime : (DateTime?)null // Or DateTime.Min or whatever value you want to use as default
UPDATE
After thinking about your problem for a couple of minutes I came up with the following code that you should never ever use ;)
using System;
class Program
{
static void Main(string[] args)
{
DateTime dt = DateTime.Now;
bool condition = true;
dynamic result = condition ?
(object)new
{
id = 1,
prop = dt
}
:
(object)new
{
id = 2,
};
Console.WriteLine(result.id);
if (condition) Console.WriteLine(result.prop);
}
}
This code should never be used in production because of it's terrible readability and it's really error prone. However, as a learning example of what's possible with the language it's quite nice.
Not directly using an if statement, but you could do it using the ternary operator (assuming TimeIn is of type DateTime):
var g = records.Select(r => new
{
Id = r.CardholderNo,
TimeIn = condition ? r.ArriveTime : (DateTime?)null;
TimeOut = r.LeaveTime
});
Note this will make the property always appear in your Annonymous Type. If this isn't the desired behavior, then you can't do it this way.
I would suggest thinking about the readability of your code and not only about "how can i shorten these few lines so it looks neat".
No. Anonymous types are just like any other type. It has a fixed list of properties. You can't dynamically add or remove properties.
I suggest to either set the property to null, like in the other answers, or use a Dictionary where you add the relevant properties and their values.
If you really need an if (or any another statement) in your Anonymous Type creation, you can try this not-so-pretty solution:
var g = records.Select(r => new
{
Id = r.CardholderNo,
TimeIn = new Func<DateTime?, DateTime?>(x =>
{
if (...)
return x;
else
return null;
}).Invoke(r.ArriveTime),
TimeOut = r.LeaveTime,
});

Inefficient IEnumerable Select Statement on XDocument

I have the following code and it is working fine. However I am new to using "IEnumerable code" and it would seem obvious that it could be done better.
Basically I want all Region nodes in the XML and then the data I want to output in my Asp:repeater is nested quite deeply in the XML, but the 4 fields are all at the same level.
var xDoc = xmlDoc.ToXDocument();
var jobs = xDoc.Descendants("Region")
.Select(x => new {
jobName = x.Element("Location").Element("Department").Element("Brand").Element("Jobs").Element("Job").Element("JobName").Value,
jobType = x.Element("Location").Element("Department").Element("Brand").Element("Jobs").Element("Job").Element("JobType").Value,
jobURL = x.Element("Location").Element("Department").Element("Brand").Element("Jobs").Element("Job").Element("URL").Value,
jobClose = x.Element("Location").Element("Department").Element("Brand").Element("Jobs").Element("Job").Element("JobCLDate").Value
}
);
if (jobs.Count() > 0)
{
careersListing.DataSource = jobs;
careersListing.DataBind();
careersListing.Visible = true;
}
I would be very grateful of any feedback with respect to making it more succinct
Thanks
Nigel
You're right; this can be inefficient.
You can simplify it like this:
var jobs = from x in xDoc.Descendants("Region")
let job = x.Element("Location").Element("Department").Element("Brand").Element("Jobs").Element("Job")
select new {
jobName = job.Element("JobName").Value,
...
};
If you prefer to use method call syntax, you can pass a statement lambda expression that declares a temporary variable.
If there is just one Job element for each region (which seems to be the case), why not just query for it directly?
var jobs = xDoc.Descendants("Job")
.Select(x => new {
jobName = x.Element("JobName").Value,
jobType = x.Element("JobType").Value,
jobURL = x.Element("URL").Value,
jobClose = x.Element("JobCLDate").Value
}
);
Another minor optimization: Use Any() instead of Count():
if (jobs.Any())
{
careersListing.DataSource = jobs;
careersListing.DataBind();
careersListing.Visible = true;
}
if (jobs.Count() > 0) can be rewritten as if (jobs.Any()).

Errors when creating a custom Querable object with MVC and Subsonic pagedlist

hiya, i have the following code but when i try and create a new IQuerable i get an error that the interface cannot be implemented, if i take away the new i get a not implemented exception, have had to jump back and work on some old ASP classic sites for past month and for the life of me i can not wake my brain up into C# mode.
Could you please have a look at below and give me some clues on where i'm going wrong:
The code is to create a list of priceItems, but instead of a categoryID (int) i am going to be showing the name as string.
public ActionResult ViewPriceItems(int? page)
{
var crm = 0;
page = GetPage(page);
// try and create items2
IQueryable<ViewPriceItemsModel> items2 = new IQueryable<ViewPriceItemsModel>();
// the data to be paged,but unmodified
var olditems = PriceItem.All().OrderBy(x => x.PriceItemID);
foreach (var item in olditems)
{
// set category as the name not the ID for easier reading
items2.Concat(new [] {new ViewPriceItemsModel {ID = item.PriceItemID,
Name = item.PriceItem_Name,
Category = PriceCategory.SingleOrDefault(
x => x.PriceCategoryID == item.PriceItem_PriceCategory_ID).PriceCategory_Name,
Display = item.PriceItems_DisplayMethod}});
}
crm = olditems.Count() / MaxResultsPerPage;
ViewData["numtpages"] = crm;
ViewData["curtpage"] = page + 1;
// return a paged result set
return View(new PagedList<ViewPriceItemsModel>(items2, page ?? 0, MaxResultsPerPage));
}
many thanks
you do not need to create items2. remove the line with comment try and create items2. Use the following code. I have not tested this. But I hope this works.
var items2 = (from item in olditems
select new ViewPriceItemsModel
{
ID = item.PriceItemID,
Name = item.PriceItem_Name,
Category = PriceCategory.SingleOrDefault(
x => x.PriceCategoryID == item.PriceItem_PriceCategory_ID).PriceCategory_Name,
Display = item.PriceItems_DisplayMethod
}).AsQueryable();

Categories