My table has a timestamp column named "RowVer" which LINQ maps to type System.Data.Linq.Binary. This data type seems useless to me because (unless I'm missing something) I can't do things like this:
// Select all records that changed since the last time we inserted/updated.
IEnumerable<UserSession> rows = db.UserSessions.Where
( usr => usr.RowVer > ???? );
So, one of the solutions I'm looking at is to add a new "calculated column" called RowTrack which is defined in SQL like this:
CREATE TABLE UserSession
(
RowVer timestamp NOT NULL,
RowTrack AS (convert(bigint,[RowVer])),
-- ... other columns ...
)
This allows me to query the database like I want to:
// Select all records that changed since the last time we inserted/updated.
IEnumerable<UserSession> rows = db.UserSessions.Where
( usr => usr.RowTrack > 123456 );
Is this a bad way to do things? How performant is querying on a calculated column? Is there a better work-around?
Also, I'm developing against Sql Server 2000 for ultimate backwards compatibility, but I can talk the boss into making 2005 the lowest common denominator.
AS Diego Frata outlines in this post there is a hack that enables timestamps to be queryable from LINQ.
The trick is to define a Compare method that takes two System.Data.Linq.Binary parameters
public static class BinaryComparer
{
public static int Compare(this Binary b1, Binary b2)
{
throw new NotImplementedException();
}
}
Notice that the function doesn't need to be implemented, only it's name (Compare) is important.
And the query will look something like:
Binary lastTimestamp = GetTimeStamp();
var result = from job in c.GetTable<tblJobs>
where BinaryComparer.Compare(job.TimeStamp, lastTimestamp)>0
select job;
(This in case of job.TimeStamp>lastTimestamp)
EDIT:
See Rory MacLeod's answer for an implementation of the method, if you need it to work outside of SQL.
SQL Server "timestamp" is only an indicator that the record has changed, its not actually a representation of Date/Time. (Although it is suppose to increment each time a record in the DB is modified,
Beware that it will wrap back to zero (not very often, admittedly), so the only safe test is if the value has changed, not if it is greater than some arbitrary previous value.
You could pass the TimeStamp column value to a web form, and then when it is submitted see if the TimeStamp from the form is different to the value in the current record - if its is different someone else has changed & saved the record in the interim.
// Select all records that changed since the last time we inserted/updated.
Is there a better work-around?
Why not have two columns, one for createddate another for lastmodifieddate. I would say that is more traditional way to handle this scenario.
Following on from jaraics' answer, you could also provide an implementation for the Compare method that would allow it to work outside of a query:
public static class BinaryExtensions
{
public static int Compare(this Binary b1, Binary b2)
{
if (b1 == null)
return b2 == null ? 0 : -1;
if (b2 == null)
return 1;
byte[] bytes1 = b1.ToArray();
byte[] bytes2 = b2.ToArray();
int len = Math.Min(bytes1.Length, bytes2.Length);
int result = memcmp(bytes1, bytes2, len);
if (result == 0 && bytes1.Length != bytes2.Length)
{
return bytes1.Length > bytes2.Length ? 1 : -1;
}
return result;
}
[DllImport("msvcrt.dll")]
private static extern int memcmp(byte[] arr1, byte[] arr2, int cnt);
}
The use of memcmp was taken from this answer to a question on comparing byte arrays. If the arrays aren't the same length, but the longer array starts with the same bytes as the shorter array, the longer array is considered to be greater than the shorter one, even if the extra bytes are all zeroes.
Related
I want to change the value of a variable called "value" which represent the shown value in the screen according to my database, here is my code
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val mViewModel = ViewModelProvider(this).get(ExpenseCalculatorViewModel::class.java)
binding.categoryName.text = args.category
val viewModel = ViewModelProvider(this).get(CategoriesViewModel::class.java)
when (binding.categoryName.text) {
getString(R.string.restaurant) -> {
viewModel.readRestaurantData.observe(viewLifecycleOwner, {
var value = 0
for (i in it.indices) {
value += it[i].restaurant
}
binding.totalNumber.text = value.toString()
})
}
please I need a useful answer and thanks for your patience
You need to perform an update query. Using ROOM for your SQLITE, you create the update query on your DAO class, you can call RestaurantDao. Allocate all your queries there such as update, delete, insert, etc.
Example: (modify the names of the table and variables according to your table structure.
#Query("UPDATE my_restaurant_table SET value=:value " +
"WHERE id=:id"
) public abstract void updateRestaurant(
long id,
String value
);
I essentially want to write a bunch of commonly used queries in a web application of this format:
SELECT *
FROM secure_table
WHERE security_function(value 1, value 2) = true;
Value 1 and value 2 will have a limited enough range of values for the idea of caching the result of the security function to be potentially very useful in improving application performance. We would also need to be able to trigger a reset of the cache at will since some conditions would render the cached values out of date.
Is there an out of the box way of doing this with SQL Server (I believe we will be using the 2012 version)? I've had a google around and seen nothing concrete, some references to ASP.NET state but nothing concrete about what that actually involves, and some references to memcached, but that wouldn't seem to go down to function level, so doesn't seem suitable either.
EDIT:
So I would like the function to work something like this:
function security_function(val1, val2) {
result = getFromCache(val1, val2)
if result is empty then
result = //do big complicated query
addToCache(val1, val2, result)
end
return result
}
If you are using ASP.Net you can use the cache object to store the results of the query:
in c#:
Results GetResults(string value1, string value2)
{
string cacheItemName = "cacheItem-" + value1 + "-" + value2;
if (Cache[cacheItemName] != null)
{
return Cache[cacheItemName];
}
else
{
var result = // do big complicated query;
Cache.Insert(cacheItemName, result,
null, DateTime.Now.AddMinutes(15d), // Expire after 15 minutes
System.Web.Caching.Cache.NoSlidingExpiration);
return result;
}
}
I have an array, lets call it _persons.
I am populating this array with Value Objects, lets call this object PersonVO
Each PersonVO has a name and a score property.
What I am trying to do is search the array &
//PSEUDO CODE
1 Find any VO's with same name (there should only be at most 2)
2 Do a comparison of the score propertys
3 Keep ONLY the VO with the higher score, and delete remove the other from the _persons array.
I'm having trouble with the code implementation. Any AS3 wizards able to help?
You'd better use a Dictionary for this task, since you have a designated unique property to query. A dictionary approach is viable in case you only have one key property, in your case name, and you need to have only one object to have this property at any given time. An example:
var highscores:Dictionary;
// load it somehow
function addHighscore(name:String,score:Number):Boolean {
// returns true if this score is bigger than what was stored, aka personal best
var prevScore:Number=highscores[name];
if (isNaN(prevScore) || (prevScore<score)) {
// either no score, or less score - write a new value
highscores[name]=score;
return true;
}
// else don't write, the new score is less than what's stored
return false;
}
The dictionary in this example uses passed strings as name property, that is the "primary key" here, thus all records should have unique name part, passed into the function. The score is the value part of stored record. You can store more than one property in the dictionary as value, you'll need to wrap then into an Object in this case.
you want to loop though the array and check if there are any two people with the same name.
I have another solution that may help, if not please do say.
childrenOnStage = this.numChildren;
var aPerson:array = new array;
for (var c:int = 0; c < childrenOnStage; c++)
{
if (getChildAt(c).name == "person1")
{
aPerson:array =(getChildAt(c);
}
}
Then trace the array,
I am importing an Excel file which is formatted like a report - that is some columns are only populated once for each group of rows that it belongs to, such as:
CaseID |Date |Code
157207 | |
|8/1/2012 |64479
|8/1/2012 |Q9967
|8/1/2012 |99203
I need to capture one of these group headers (CaseID, in the example above) and use it for subsequent rows where the field is blank, then save the next value that I encounter.
I have added a variable (User::CurrentCaseId) and a Script transform, with the following code:
public class ScriptMain : UserComponent
{
string newCaseId;
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
if (!Row.CaseIDName_IsNull && Row.CaseIDName.Length > 0)
newCaseId = Row.CaseIDName;
else
newCaseId = "DetailRow";
}
public override void PostExecute()
{
base.PostExecute();
if (newClaimNumber != "DetailRow")
Variables.CurrentCaseId = newCaseId;
}
Basically, I am trying to read the value when present and save it in this variable. I use a conditional split to ditch the rows that only have the CaseID and then use a derived column to put the variable value into a new column to complete the detail row.
Alas, the value is always blank (placed a data viewer after the derived column). I modified the script to always set the variable to a fixed string - the derived column is still blank.
This seemed like a good plan... I received some feedback in the MS forums that you can't set a variable value and use its new value within the same Data Flow Task. If that is so, the only solution I can think of is to write the CaseID out to a table when present and read it back in when absent. I really hate to do that with several million rows (multiple Excel worksheets). Any better ideas?
Best,
Scott
This can be a good starting point for you.
I used the following file as the source. Saved it into C:\Temp\5.TXT
CaseID |Date |Code
157207 | |
|8/1/2012 |64479
|8/1/2012 |Q9967
|8/1/2012 |99203
157208 | |
|9/1/2012 |77779
|9/2/2012 |R9967
|9/3/2012 |11203
Put a DFT on the Control Flow surface.
Put Script Component as Source on the DFT
3.1. Go to Inputs and Outputs section
3.2. Add Output. Change it name to MyOutput.
3.2.1 Add the following output columns - CaseID, Date, Code
3.2.1 The data types are four-byte unsigned integer [DT_UI4], string [DT_STR], string [DT_STR]
Now go to Scripts // Edit Script. Put the following code. Make sure to add
using System.IO;
to the namespace area.
public override void CreateNewOutputRows()
{
string[] lines = File.ReadAllLines(#"C:\temp\5.txt");
int iRowCount = 0;
string[] fields = null;
int iCaseID = 0;
string sDate = string.Empty;
string sCode = string.Empty;
foreach (string line in lines)
{
if (iRowCount == 0)
{
iRowCount++;
}
else
{
fields = line.Split('|');
//trim the field values
for (int i = 0; i < fields.Length; i++)
{
fields[i] = fields[i].Trim();
}
if (!fields[0].Equals(string.Empty))
{
iCaseID = Convert.ToInt32(fields[0]);
}
else
{
MyOutputBuffer.AddRow();
MyOutputBuffer.CaseID = iCaseID;
MyOutputBuffer.Date = fields[1];
MyOutputBuffer.Code = fields[2];
}
}
}
}
}
Testing your code: Add a Union All components right beneath where you put the Script component. Connect the output of the Script component to the Union All component. Put data viewer.
Hopefully this should help you. Please let us know. I responded to a similar question today; please check that one out as well. That may help in solidfying the concept - IMHO.
The following is the C# code and generated SQL in a LINQ to SQL query for two cases.
Case 1
using (JulianDataContext dc = new JulianDataContext(this.CurrentConnectionString))
{
#if DEBUG
dc.Log = new DebugTextWriter();
#endif
IEnumerable<UserNewsfeedDeliveryTime> temp = dc.UserNewsfeedDeliveryTimes.Where(u => u.NewsfeedEmailPeriodicity > 0 && DateTime.Today >= u.NextNewsfeedDelivery.Value.Date);
ids = temp.Select(p => p.Id).ToList();
}
SELECT [t0].[Id], [t0].[NewsfeedEmailPeriodicity], [t0].[LastSentNewsfeedEmail], [t0].[NextNewsfeedDelivery]
FROM [dbo].[UserNewsfeedDeliveryTimes] AS [t0]
WHERE ([t0].[NewsfeedEmailPeriodicity] > #p0) AND (#p1 >= CONVERT(DATE, [t0].[NextNewsfeedDelivery]))
-- #p0: Input Int (Size = -1; Prec = 0; Scale = 0) [0]
-- #p1: Input DateTime (Size = -1; Prec = 0; Scale = 0) [15-11-2012 00:00:00]
Case 2
using (JulianDataContext dc = new JulianDataContext(this.CurrentConnectionString))
{
#if DEBUG
dc.Log = new DebugTextWriter();
#endif
IEnumerable<UserNewsfeedDeliveryTime> temp = dc.GetTable<UserNewsfeedDeliveryTime>();
temp = temp.Where(u => u.NewsfeedEmailPeriodicity > 0 && DateTime.Today >= u.NextNewsfeedDelivery.Value.Date);
ids = temp.Select(p => p.Id).ToList();
}
SELECT [t0].[Id], [t0].[NewsfeedEmailPeriodicity], [t0].[LastSentNewsfeedEmail], [t0].[NextNewsfeedDelivery]
FROM [dbo].[UserNewsfeedDeliveryTimes] AS [t0]
The difference
The difference between these two linq queries:
dc.UserNewsfeedDeliveryTimes
and
dc.GetTable<UserNewsfeedDeliveryTime>()
Why? Could it be that, in case 2, LINQ to SQL is retrieving all data from database and finish the query by filtering all objects in memory?
If so, how can we make keep this generic and still force all the T-SQL to be generated?
Solution
Both answers, are correct but I had to pick one, sorry! I think also it is interesting to add that in this case, since I changed to work with an IQueryable (inherits from IEnumerable), in this line:
temp = temp.Where(u => u.NewsfeedEmailPeriodicity > 0 && DateTime.Today >= u.NextNewsfeedDelivery.Value.Date);
I had two overload methods, one from the IQueryable interface and another to the IEnumerable interface.
public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
So I had to convert my predicate explicitly to Expression> predicate, otherwise the IEnumerable interface method would have been picked up at compile time and, if I am not mistaken, I would get some dynamic sql exception saying the T-SQL could not have been generated.
From my understanding, IEnumerable does not transform the original query information that IQueryable holds. It's almost as if the cast freezes any changes to the IQueryable query at the point of casting. If you look at MSDN, it turns out that IQueryable inherits IEnumerable:
http://msdn.microsoft.com/en-us/library/system.linq.iqueryable.aspx
Hence, you see this behaviour. It is important with LINQ-SQL to work with IQueryable unless you want the query frozen at the point it is turned to an IEnumerable.
In your first example, the where is inclusive of the original query. The select is not hence the query generated.
In your second example, you capture the table itself into an IEnumerable. Any changes on top of this are done in memory on top of the original query.
When you think, the IEnumerable version of where will not be able to transform the original data of the IQueryable due to the cast and how inheritance works.
When you also consider deferred loading, and how LINQ works, this seems to make sense.
To me it is a big annoyance, as it can lead you into generating some terrible performing code.
Try using IQueryable instead of IEnumerable.
Weird, because on my examples I get the opposite results from you, ie with IEnumerable, case 1 works fast and case 2 retrieves all the data. But using IQueryable fixes the issue.