Can I get values from my database using this method but without generating the additional text? - linq

I am very new to programming and I can't seem to find a way around this. Maybe there is also a better way.
I am trying to get 2 values out of a single row in my database. I have connected to it using EF.
My code is:
using (var myEntities = new dataEntities())
{
var myValues = (from values in myEntities.PointValues
where values.PointID == dataValue && values.DataTime >= fromDate && values.DataTime <= toDate
select new
{ values.DataTime,
values.DataValue
}).ToList();
I then write them to a file with this code:
using (StreamWriter sw = new StreamWriter(#"c:\Test.csv"))
{
for (var i = 0; i < myValues.Count; i++)
{
sw.WriteLine(myValues[i]);
}
}
The problem is the resulting CSV file is like this:
{ DataTime = 1/20/2010 2:15:00 AM, DataValue = 11.72 }
How do I get rid of the { DataTime =, DataValue and the closing }? (DataTime and DataValue are the field labels in the database).
Many thanks for any assistance.
Kind regards,
Julian

You just need to change how you write out the information:
using (var sw = new StreamWriter(#"c:\Test.csv"))
{
foreach(var value in myValues)
{
sw.WriteLine(string.Format("{0}, {1}", value.DataTime, value.DataValue));
}
}
Right now, you're writing out the anonymous class directly, instead of creating the output formatted as needed.
Alternatively, you could build the string directly in your query and write the results easily using:
var myValues = (from values in myEntities.PointValues
where values.PointID == dataValue && values.DataTime >= fromDate && values.DataTime <= toDate
select new
{ values.DataTime,
values.DataValue
})
.AsEnumerable()
.Select(v => string.Format("{0}, {1}", v.DataTime, v.DataValue));
File.WriteAllLines(#"c:\Test.csv", myValues);
This would just build a IEnumerable<string> instead of building the anonymous class.
I would use this approach if you're not using the query results for anything other than writing to the file. If you're using the anonymous class in other code in between, the first is going to keep you from needing to change that code.

Add another select at the end.
var myValues = (from values in myEntities.PointValues
where values.PointID == dataValue
&& values.DataTime >= fromDate
&& values.DataTime <= toDate
select new
{ values.DataTime,
values.DataValue
})
.ToList()
.Select(x => string.Format("{0}, {1}", x.DateTime, x.DataValue);
Additionally, if you don't need bells & whistles of the StreamWriter you could also use File.WriteAllLines():
File.WriteAllLines(#"c:\Test.csv", myValues);
(updated per Reed's post)

Related

Restrict records returned from nested LINQ statement

how would I restrict the "Charges" returned in this linq query, to a specified date range:
var dte = DateTime.Parse("2012-01-01");
var dte2 = DateTime.Parse("2012-02-01");
var meetingrooms = tblMeetingRoom
.Where(r => r.building_id==1)
.GroupBy(p => p.tblType)
.Select(g => new
{
TypeName = g.Key.room_type,
TypeID = g.Key.type_id,
TypeCount = g.Count(),
charges =
from rt in charges
where (rt.type_id == g.Key.type_id)
select new {
rt.chargedate,
rt.people,
rt.charge
}
});
meetingrooms.Dump();
I think it needs to go inbetween here somehwhere:
from rt in charges
where (rt.type_id == g.Key.type_id) (EG) && rt.chargedate>=dte and rt.chargedate <dte2
select new {
Thanks for any help,
Mark
from rt in charges
where rt.type_id == g.Key.type_id && (rt.chargedate >= dte && rt.chargedate <= dte2)
select new {
.....
#Maarten - I've been trying this for ages - LinqPad kept giving errors, so I was trying all different ways I could think of - for whatever reason, I must have made some typos, that I didn't make above!
Sorry for wasting everyone's time - the above works "as-is"!
Mark

How to get all the birthdays of today?

Does anyone know how to make a Linq query that gets all the birthdays of today? The code below doesn't work :
var getBirthdays =
orgContext.CreateQuery<Contact>()
.Where(c => c.BirthDate != null
&& c.BirthDate.Value.Month == DateTime.Now.Month).ToList();
I get an error like this:
"Invalid 'where' condition. An entity member is invoking an invalid
property or method."
Thanks in advance!
Anytime a vendor writes a four part blog series on how to do something as simple as finding a birthday (as Microsoft did in 2007), you have to know this won't be simple. So far as I can tell, this hasn't updated since then.
Find contacts with upcoming birthdays
Find contacts with upcoming birthdays - Part 2
Find contacts with upcoming birthdays - Parts 3 and 4
So you have limited options:
Make new fields called something like new_birthmonth and new_birthday that's updated every time a contact is created or updated via a plugin, and then query on those int fields.
Using Dynamic Linq, construct an OR clause in your WHERE clause that checks to see if the birthday falls in a reasonable range of years (say, 140 for the long-livers) (code below).
List<string> birthdays = new List<string>(); //will contain list of OR clauses
//makes sure no CRM unsupported dates are passed (less than 1/1/1900)
for (int i = Math.Min(140, DateTime.Today.Year - 1900); i > -1; i--)
{
//adds a different date per year
birthdays.Add
(
string.Format
(
//DateTimes are stored in UTC
"BirthDate = DateTime.Parse(\"{0}\")",
DateTime.Today.ToUniversalTime().AddYears(-i)
)
);
}
//completes the correct dynamic linq OR clause
string birthdayList = string.Join(" OR ", birthdays);
var getBirthdays = orgContext.CreateQuery<Xrm.Contact>()
.Where(c => c.BirthDate != null)
.Where(birthdayList)
.ToList();
I solved my problem based on the example of "Peter Majeed" and using "LinqKit"!
var predicate = PredicateBuilder.False<Contact>();
for (int i = Math.Min(140, DateTime.Today.Year - 1900); i > -1; i--)
{
DateTime cleanDateTime = new DateTime(DateTime.Today.AddYears(-i).Year, DateTime.Today.AddYears(-1).Month, DateTime.Today.AddYears(-i).Day);
predicate = predicate.Or(p => p.BirthDate == cleanDateTime.ToUniversalTime());
}
var getBirthdays = (from c in orgContext.CreateQuery<Contact>().AsExpandable().Where(predicate)
select c).ToList();
The above query gave me the correct result! Thx to all who helped me!
If c.BirthDate is nullable, you have to convert it to a datetime first:
var getBirthdays = orgContext.CreateQuery<Contact>()
.Where(c => c.BirthDate != null &&
(Convert.ToDateTime(c.BirthDate).Month ==
DateTime.Now.Month) &&
Convert.ToDateTime(c.BirthDate).Day ==
DateTime.Now.Day))
.ToList();
You could fetch this info with a Query, if that is possible in your situation?
//set up the condition + filter
var ce = new Microsoft.Xrm.Sdk.Query.ConditionExpression();
ce.Operator = Microsoft.Xrm.Sdk.Query.ConditionOperator.LastXDays;
ce.AttributeName = "birthdate";
ce.Values.Add(30);
var fe = new Microsoft.Xrm.Sdk.Query.FilterExpression();
fe.AddCondition(ce);
//build query
var query = new Microsoft.Xrm.Sdk.Query.QueryExpression();
query.EntityName = "contact";
query.Criteria.AddFilter(fe);
//get results
var results = CrmHelperV5.OrgProxy.RetrieveMultiple(query);
//if you want early bound entities, convert here.
var contacts = new List<Contact>();
foreach(var result in results.Entities)
{
contacts.Add(result.ToEntity<Contact>());
}
You may want to investigate the other operators for the filters + conditions
You can use QueryExpression (it works for Microsoft CRM Plugin)
public EntityCollection getBirthdateList(IOrganizationService orgsService)
{
List<string> birthdays = new List<string>();
//makes sure no CRM unsupported dates are passed (less than 1/1/1900)
for (int i = Math.Min(140, DateTime.Today.Year - 1930); i > -1; i--)
{
//adds a different date per year
birthdays.Add
(
DateTime.Now.AddYears(-i).ToString("yyyy-MM-dd")
);
}
// Instantiate QueryExpression
var query = new QueryExpression("contact");
// Define filter QEquote.Criteria
var queryfilter = new FilterExpression();
query.Criteria.AddFilter(queryfilter);
// Define filter
queryfilter.FilterOperator = LogicalOperator.Or;
queryfilter.AddCondition("birthdate",ConditionOperator.In,birthdays.ToArray());
return orgsService.RetrieveMultiple(query); ;
}

How to join results from two different sets in LINQ?

I get some data about customers in my database with this method:
public List<KlientViewModel> GetListOfKlientViewModel()
{
List<KlientViewModel> list = _klientRepository.List().Select(k => new KlientViewModel
{
Id = k.Id,
Imie = k.Imie,
Nazwisko = k.Nazwisko,
Nazwa = k.Nazwa,
SposobPlatnosci = k.SposobPlatnosci,
}).ToList();
return list;
}
but also I have another method which counts value for extra field in KlientViewModel - field called 'Naleznosci'.
I have another method which counts value for this field based on customers ids, it looks like this:
public Dictionary<int, decimal> GetNaleznosc(List<int> klientIds)
{
return klientIds.ToDictionary(klientId => klientId, klientId => (from z in _zdarzenieRepository.List()
from c in z.Klient.Cennik
where z.TypZdarzenia == (int) TypyZdarzen.Sprzedaz && z.IdTowar == c.IdTowar && z.Sprzedaz.Data >= c.Od && (z.Sprzedaz.Data < c.Do || c.Do == null) && z.Klient.Id == klientId
select z.Ilosc*(z.Kwota > 0 ? z.Kwota : c.Cena)).Sum() ?? 0);
}
So what I want to do is to join data from method GetNaleznosc with data generated in method GetListOfKlientViewModel. I call GetNaleznosc like this:
GetNaleznosc(list.Select(k => k.Id).ToList())
but don't know what to do next.
Having obtained the dictionary:
var dict = GetNaleznosc(list.Select(k => k.Id).ToList());
You can now efficiently look up the decimal value of Naleznosci for a given client:
foreach (var k in list)
k.Naleznosci = dict[k.Id];
Now you have merged the values into the main list. Is this what you mean?
By the way, in your function that builds the dictionary, you make it accept a List<int>, but then all you do is call ToDictionary on it, which only requires IEnumerable<int>. So change the parameter type to that, and then you can call it:
var dict = GetNaleznosc(list.Select(k => k.Id));
This removes the call to ToList, which avoids making an unnecessary intermediate copy of the whole list of Ids. Probably won't make much difference in this case if you're hitting a database and then building up a large set of results in memory, but maybe worth bearing in mind for other uses of these operations.
Also, looking again at the helper function, there is no apparent advantage in building up the set of results in a dictionary for a list of ids, because each one is handled independently. You could simply put:
public decimal GetNaleznosc(int klientId)
{
return (from z in _zdarzenieRepository.List()
from c in z.Klient.Cennik
where z.TypZdarzenia == (int) TypyZdarzen.Sprzedaz && z.IdTowar == c.IdTowar && z.Sprzedaz.Data >= c.Od && (z.Sprzedaz.Data < c.Do || c.Do == null) && z.Klient.Id == klientId
select z.Ilosc*(z.Kwota > 0 ? z.Kwota : c.Cena)).Sum() ?? 0);
}
That is, provide a function that discovers just one value. Now you can directly build the right list:
public List<KlientViewModel> GetListOfKlientViewModel()
{
return _klientRepository.List().AsEnumerable().Select(k => new KlientViewModel
{
Id = k.Id,
Imie = k.Imie,
Nazwisko = k.Nazwisko,
Nazwa = k.Nazwa,
SposobPlatnosci = k.SposobPlatnosci,
Naleznosci = GetNaleznosc(k.Id)
}).ToList();
}

date difference with linq

With this code:
i.SpesaAlloggio = db.TDP_NotaSpeseSezB.Sum(p => p.Costo / (((DateTime)p.DayEnd)
.Subtract((DateTime)p.DayStart).Days + 1));
I receive this error:
LINQ to Entities does not recognize the method
'System.TimeSpan Subtract(System.DateTime)' method, and this method cannot be
translated into a store expression.
How can I do this?
Use a calculated DB field and map that. Or use SqlFunctions with EF 4 as LukLed suggested (+1).
I wrote a function for removing time:
public static DateTime RemoveHours(DateTime date)
{
int year = date.Year;
int month = date.Month;
int day = date.Day;
return new DateTime(year, month, day);
}
and changed filtering condition:
var query =
from trn in context.IdentityTransactions
where trn.ClientUserId == userId && trn.DateDeleted == null
orderby trn.DateTimeCreated
select new
{
ClientServerTransactionID = trn.ClientServerTransactionID,
DateTimeCreated = trn.DateTimeCreated,
ServerTransDateTime = trn.ServerTransDateTime,
Timestamp = trn.Timestamp,
Remarc = trn.Remarc,
ReservedSum = trn.ReservedSum,
};
if (dateMin.HasValue && dateMin.Value > DateTime.MinValue)
{
DateTime startDate = Converters.RemoveHours(dateMin.Value);
query = from trn in query
where trn.DateTimeCreated >= startDate
select trn;
}
if (dateMax.HasValue && dateMax.Value > DateTime.MinValue)
{
var endDate = Converters.RemoveHours(dateMax.Value.AddDays(1.0));
query = from trn in query
where trn.DateTimeCreated < endDate
select trn;
}
dateMin and dateMax are nullable types and may be not set in my case.
Try (it is not very efficient, but it will work):
i.SpesaAlloggio = db.TDP_NotaSpeseSezB.ToList()
.Sum(p => p.Costo / (((DateTime)p.DayEnd)
.Subtract((DateTime)p.DayStart).Days + 1));
EDIT : This will be extremely slow for large tables, because it transfers whole table content form server
Entity Framework tries to translate your expression to SQL, but it can't handle ((DateTime)p.DayEnd).Subtract((DateTime)p.DayStart). You have to make it simpler. ToList() gets all rows and then makes the calculation on application side, not in database.
With EF4, you could use SqlFunctions DateDiff
With EF1, you could create calculated field or view with this field and make calculation based on this field.

Linq To Nhibernate - Separated queries

I've got the following situation:
var totalRecords = (from entry in invalidAccEntryRepository
select entry).Where(entry =>
entry.CustomerAccountInfo.CustomerAccountName == CustomerAccountName &&
entry.CustomerAccountInfo.CustomerAccountId == CustomerAccountId).Count();
vs.
var totalRecords = (from entry in invalidAccEntryRepository
select entry);
if (CustomerAccountInfoFilterActive)
{
totalRecords.Where(entry =>
entry.CustomerAccountInfo.CustomerAccountName == CustomerAccountName &&
entry.CustomerAccountInfo.CustomerAccountId == CustomerAccountId);
}
totalRecordsCount = totalRecords.Count();
The first query works completely but the second query only executes the only
var totalRecords = (from entry in invalidAccEntryRepository
select entry);
and ignores the conditionally added where expression.
Anyone know what the problem could be? Do you need more info?
Thx in advance!
You aren't actually applying the where. In your if, use this instead:
totalRecords = totalRecords.Where(entry =>
entry.CustomerAccountInfo.CustomerAccountName == CustomerAccountName &&
entry.CustomerAccountInfo.CustomerAccountId == CustomerAccountId);

Resources