I'm creating a synchronize function between a device and server for a large database. I have a lot of listing tables (the items in a dropdown/picker).
I don't want to write a lot of code and I'm looking for an elegant solution :)
On a device in SQLite I defined listing table like
public class NameTable : IBusinessEntity {
public int Id { get; set; } = 0;
public string Description { get; set; }
}
When I save in database a new record (item) I call this function
public int SaveItem<T>(T item) where T : IBusinessEntity {
lock (locker) {
if (item.Id != 0) {
database.Update(item);
return item.Id;
}
else {
return database.Insert(item);
}
}
}
Now when the device receives a new record from the server the structure is like
public class SyncResult {
public int DeviceId { get; set; }
public int ServerId { get; set; }
public string TableName { get; set; }
public string Description { get; set; }
}
Then I want to save (insert a new record if DeviceId == 0 or update an existing item).
My question is: how can I call SaveItem where T is the TableName from SyncResult?
Thank you in advance for any help (I can offer a beer for that!)
SaveItem is a member of MyDatabase class. Basically my problem is how to pass to SaveItem<T> the T as string.
I don't know if I explained clearly my issue.
You could map a TableName to a Type for example Dictionary<string,Type> Use the Activator class to construct the type. Use reflection to fill the data.
Related
So I'm trying to store a record in the databse using dapper. I'm passing an object to the method where I have my query to store the recorde. Let me be more clear. Below is my model :
public class Foo
{
public long FooId { get; set; }
public Guid Foo2ID { get; set; }
public string Status { get; set; }
public Person Person { get; set; } = new Person();
}
public class Person
{
public string Type { get; set; }
public string Character { get; set; }
public DateTime Test { get; set; }
}
And this is my query :
public async Task<ActionResult> Create(Foo f)
{
using (var connection = _dbAccess.CreateConnection())
{
var sqlStatement = #"
INSERT INTO ReportRequests
(FooId
,Foo2Id
,Person
,Status)
VALUES
(#FooId
#,Foo2Id
#,Person
#,Status)";
await connection.ExecuteAsync(sqlStatement, f);
};
return Ok();
}
I'm trying to save a json in the Person column in the database. But I get this error :
The member x of type x cannot be used as a parameter value
Can anyone please give me an idea on how I can approach to this problem. It would be very helpful.
Thank you a lot :)
enter code hereFirst of all, you should consider whether you can use LINQ-like queries with dapper. It makes it both more readable and avoids having issues like that.
Back to your problem, from the code you posted it looks like you've misplaced the comas after the # symbol #,Foo2Id :
(#FooId
#,Foo2Id
#,Person
#,Status)
It should be:
(#FooId
#Foo2Id,
#Person,
#Status)
Is this possible? I am trying to avoid a lot of copying and pasting from area to area. I have a search function (I have reduced the code for simplicity).
if (!String.IsNullOrEmpty(filterVM.searchString))
{
var nameSearch = filterVM.searchString.ToLower();
guests = guests.Where(g => g.FirstName.ToLower().StartsWith(nameSearch)
|| g.LastName.ToLower().StartsWith(nameSearch)
)
}
filterVM.FilteredResultsCount = guests.CountAsync();
Guests can change from area to area, but it always has the same base things, like FirstName and LastName,
ex:
public class GuestBasicBase
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string GuestGuid { get; set; } = Guid.NewGuid().ToString();
public string FirstName { get; set; }
public string LastName { get; set; }
}
Then I can have a bigger class for a particular area like
public class AreaOneGuest : GuestBasicBase
{
public int ID {get; set;}
public string ExtraFieldOne { get; set; }
public string ExtraFieldTwo { get; set; }
//Etc
}
I would like to have a function which will return a viewmodel and part of that viewmodel is PaginatedList and the other part is the Filter parameters, like this:
public class GuestBasicBaseIndexVM
{
public PaginatedList<T:GuestBasicBase> Guests { get; set; }
public GuestIndexFilterVM FilterVM { get; set; }
}
And I want a function to return this but take in a larger field, like
public async Task<GuestBasicBaseIndexVM>(T:GuestBasicBase, GuestIndexFilterVM filterVM){
//do search function
return (T where T: GuestBasicBase)
}
Does this question make sense and is it possible? Currently trying on my own and seeing what happens...I feel like it is sort of like the PaginatedList class but I am not certain
Not exactly what I wanted, but here is what I did. changed my BaseViewModel like this:
public class GuestBasicBaseIndexVM
{
public IEnumerable<GuestBasicBase> Guests { get; set; }
//Changed from a PaginatedList
public GuestIndexFilterVM FilterVM { get; set; }
}
and this function:
public static async Task<GuestBasicBaseIndexVM> CreateUpdatedGuestList(GuestIndexFilterVM filterVM, IQueryable<GuestBasicBase> guests)
{
//Code to search through guests and return filtered list and filters viewmodel
}
Then after the Ienumaerable of basic guests is returned I did this to connect them back to the AreaOne Guests
var x = await Helpers.CreateUpdatedGuestList(filterVM, guests);
var hsIDs = x.Guests.Select(v => v.GuestGuid).ToHashSet(); //Filtered GuestGuids to hashset
areaOneGuests = guests.Where(g => hsIDs.Contains(g.GuestGuid)) //This matches up the filtered list of base guests to the actual full guests.
//Then whatever code to do what I want with the AreaOne Guests....
It wasn't exactly what I was trying to do, but still saves me a lot of copying and pasting from area to area with similar base Guest classes. Have not been able to measure any noticeable performance loss/gain doing it this way.
I've developed an UWP app where I use a SQLite database to store datas that are synced.
Among these data, there a lot of tables that contain translated data. For example, for various cases, we have:
a "businness" table, which contains the id that is really used in the database
a "translation" table, which contains transaltion for the business table
The models of the "business" tables are defined like this:
public class Failure_Type : BasePoco
{
[PrimaryKey, NotNull]
public int failure_id { get; set; }
public int? function_type_id { get; set; }
public int? component_category_id { get; set; }
[MaxLength(200), NotNull]
public string description { get; set; }
public DateTime? disable_date { get; set; }
[Ignore]
public string _descriptionTr { get; set; }
}
The field "description" stores the english/default description, and the "_descriptionTr" field will store the translated description.
The models of the "translation" tables are defined like this:
public class Failure_Type_Translation : BasePoco
{
[PrimaryKey, NotNull]
public int failure_type_translation_id { get; set; }
public int? failure_type_id { get; set; }
[MaxLength(2)]
public string language { get; set; }
[MaxLength(200), NotNull]
public string description { get; set; }
}
The field "failure_type_id" is related to the business table, the other fields store the language code and the related translation.
So, after syncing datas in the SQLite database, I refresh the "translated" datas in the app and this can take a long moment. The load of the the 2 tables from the SQLite is very quickly, but the update of the "_descriptionTr" field can be very slow:
var failureType = ServiceLocator.Current.GetInstance<IRepository>().GetAll<Failure_Type>();
var failureTypeTranslations = ServiceLocator.Current.GetInstance<IRepository>().GetAll<Failure_Type_Translation>();
FailureType = new ObservableCollection<Failure_Type>();
foreach (var ft in failureType)
{
var ftt = failureTypeTranslations.FirstOrDefault(i => i.failure_type_id == ft.failure_id && i.language.ToLower().Equals(lang));
if (ftt != null)
ft._descriptionTr = ftt.description;
else
ft._descriptionTr = ft.description;
FailureType.Add(ft);
}
Is there a better way for doing this?
How could I optimize it?
Edit :
the "business" table contains 550 rows
the "translation" table contains 3500 rows
the duration of the loop is nearly 1 minute
A couple of suggestions:
Create the observable collection at once ...
FailureType = new ObservableCollection<Failure_Type>(failureType);
... so the individual additions don't fire notifications. Now use FailureType in the loop.
Instead of fetching all translations, filter them by lang:
var failureTypeTranslations = ServiceLocator.Current.GetInstance<IRepository>()
.GetAll<Failure_Type_Translation>()
.Where(l => i.language == lang);
Create a dictionary for lookup of known translations:
var dict = failureTypeTranslations.ToDictionary(ftt => ftt.failure_id);
foreach (var ft in FailureType)
{
Failure_Type_Translation ftt;
if (dict.TryGetValue(ft.failure_id, out ftt)
ft._descriptionTr = ftt.description;
else
ft._descriptionTr = ft.description;
}
I think that esp. the part failureTypeTranslations.FirstOrDefault kills performance. The query is executed for each iteration of the loop.
I am creating a simple blogging application to get .NET MVC 4 down and I am having a problem. Everything works except for when I try to tag a blog using an array of strings for each blog like so:
public class BlogEntry
{
public List<Comment> BlogComments { get; set; }
public virtual List<String> RawTags { get; set; }
public virtual List<Tag> BlogTags { get; set; }
public virtual User Author { get; set; }
public int AuthorId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public DateTime DatePosted { get; set; }
[Key]
public int Id { get; set; }
public bool IsAcceptingComments { get; set; }
public bool IsVisible { get; set; }
public DateTime LastEdited { get; set; }
}
public class Tag
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int RefCount { get; set; }
}
Upon creating a blog and tagging it, I save tags into the BlogEntry model using this:
[HttpPost]
public int Create(string data)
{
if (data != null)
{
BlogEntry newBlog = JsonConvert.DeserializeObject<BlogEntry>(data);
newBlog.Author = Session["user"] as User;
newBlog.AuthorId = newBlog.Author.Id;
newBlog.IsVisible = true;
newBlog.IsAcceptingComments = true;
newBlog.LastEdited = DateTime.Now;
newBlog.DatePosted = DateTime.Now;
newBlog.BlogTags = new List<Tag>();
foreach (String s in newBlog.RawTags)
{
// First check to see if the tag already exists
Tag check = Db.Tags.Where(m => m.Name == s).FirstOrDefault();
if (check != null)
{
check.RefCount++;
newBlog.BlogTags.Add(check);
Db.Tags.Attach(check);
Db.Entry(check).State = System.Data.Entity.EntityState.Modified;
Db.SaveChanges();
}
else
{
// Create a new tag
Tag newTag = new Tag();
newTag.Name = s;
newTag.RefCount = 1;
newBlog.BlogTags.Add(newTag);
Db.Tags.Add(newTag);
}
}
Db.BlogEntries.Add(newBlog);
Db.SaveChanges();
return newBlog.Id;
}
return -1;
}
First I do a check to see if a tag already exists.. If it does, I try to add the same tag, check to the newBlog object. I would have thought that this would just save a reference to this Tag object in the DbSet, however, if I create multiple blogs posts with the tag "html" and then run a query to see what blogs have the html tag, only the most recently tagged blog retains this value.... What can I do so that I can have multiple BlogEntry objects with the same Tag object in the database?
I don't have my dev machine in front of me right now, so this is just a guess, but I figure it's better than making you wait until tomorrow...
I don't think you need the last 3 lines in your if(check!=null) and in fact, I wonder if they aren't messing you up:
Db.Tags.Attach(check);
Db.Entry(check).State = System.Data.Entity.EntityState.Modified;
Db.SaveChanges();
You shouldn't need to attach because you got it from the Db object already, so it should already be being tracked. This means you don't need to change the state and as for the SaveChanges, you are going to do that below.
And now another disclaimer: I've done some work with Entity Framework (version 6, if you want to know), but not with MVC, so it may be different, but my understanding is that it is better to create a new DbContext for each set of instructions, rather than having a class variable that just tracks running changes. I'm not sure if that is what you are doing or not, but it sort of looks that way from this code sample. Assuming that is relevant in MVC, you may consider creating a new DbContext (Db) at the top of your create method.
Let me know how it goes--if this doesn't help, I'll delete this answer.
First you would have to update the Tag class so that it can track its registered blog entries itself. Here the BlogEntry and Tag classes have a many-to-many relationship. So the Tag class would look like below:
public class Tag
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int RefCount { get; set; }
public virtual List<BlogEntry> BlogEntries { get; set; } // MODIFICATION
}
Now you have to add the blog entry to all of its tags for back referencing to meet your query in an easy way. Look for the modifications I have made in the for-loop below:
foreach (String s in newBlog.RawTags)
{
// First check to see if the tag already exists
Tag check = Db.Tags.Where(m => m.Name == s).FirstOrDefault();
if (check != null)
{
check.RefCount++;
check.BlogEntries.Add(newBlog); // MODIFICATION
newBlog.BlogTags.Add(check);
Db.Tags.Attach(check);
Db.Entry(check).State = System.Data.Entity.EntityState.Modified;
Db.SaveChanges();
}
else
{
// Create a new tag
Tag newTag = new Tag();
newTag.Name = s;
newTag.RefCount = 1;
newTag.BlogEntries = new List<BlogEntry>(); // MODIFICATION
newTag.BlogEntries.Add(newBlog); // MODIFICATION
newBlog.BlogTags.Add(newTag);
Db.Tags.Add(newTag);
}
}
To see what blogs have the html tag, you just have to query on the Tag class and search through the BlogEntries to get the desired blogs. Good luck!
Let's say I have the following document structure:
{
"_id" : id,
"name" : "Tom Cruise",
"movies" : [
{
"movie_id" : id,
"name" : "Mission Impossible",
"yr_released": 1996
},
{
"movie_id" : id,
"name" : "Minority Report",
"yr_released": 2002
}
]
}
Here are my POCO's:
public class Actor
{
[BsonId]
public int Id { get; set; }
[BsonElement("name")]
public string Name { get; set; }
[BsonElement("movies")]
public List<Movies> Movies { get; set; }
}
public class Movies
{
[BsonId]
public int Id { get; set; }
[BsonElement("name")]
public string Name { get; set; }
[BsonElement("yr_released")]
public int YearReleased
}
Let's say the next day, the document gets updated but the last movie name gets changed from "Minority Report" to "Vanilla Sky". I want to find out what changed in the sub documents. This is the sample code that I used (which doesn't work):
var yesterdayQuery = (yesterdayColl.AsQueryable<Actor>()
.Where (b => b.Name.Contains("Cruise"))).ToList();
var todayQuery = (todayColl.AsQueryable<Actor>()
.Where (b => b.Name.Contains("Cruise"))).ToList();
var diff = todayQuery.Except(yesterdayQuery);
Since Mongodb's C# driver doesn't have Except() support, I thought that if I used Linq to Objects as a workaround, I would be able to find the difference. I guess I was wrong. Basically, I would like to find the following differences between the documents:
If a property value has been changed
If a document or sub-document has been deleted
If a sub-document has been added
My question is: How can I write a strongly-typed query using the C# driver (hopefully) to achieve this?
If you want to know what changed and not just if it was changed it isn't really a MogngoDB question.
you need 2 copies of your data. Then you need to go property by property (with reflection if you want it to be more generic) and get the new values.
The old copy can be saved in the DB and the new one only in memory.
I'm not familiar with MongoDB, but I think you would write your class like this:
public class Actor
{
// equal objects must have equal hash codes
public override int GetHashCode()
{
return Id.GetHashCode();
}
// objects with the same Id are equal
public override bool Equals(object obj)
{
Actor other = obj as Actor;
if (other == null)
return false;
return this.Id == other.Id;
}
[BsonId]
public int Id { get; set; }
[BsonElement("name")]
public string Name { get; set; }
[BsonElement("movies")]
public List<Movies> Movies { get; set; }
}