I'm currently about to develop a website with asp.net mvc4 and mongodb as database. As the Microsoft Membership Provider does only support SQL-DB's, I've to use another Membership Provider. I decided to use the ExtendedMongoMembership Provider. Everything worked as long as I had no additional user properties passed during the Account creation. As I tried to add some additional properties like e-mail, the functionality of the CreateUserRow function throws and exception. I've downloaded the source and try to fix it. Therefore I have to separate objects inside of objects, that seems to be the way how the necessary data is passed into the function.
public bool CreateUserRow(string userName, IDictionary<string, object> values)
{
string userTableName = "Users";
List<BsonElement> elements = new List<BsonElement>();
elements.Add(new BsonElement("UserName", userName));
elements.Add(new BsonElement("_id", GetNextSequence("user_id")));
if (values != null)
{
// Here I'm facing the problem where I have to get the property names
// and the values to add them to the elements list
// The IDictionary is unfortunately not build in the way
// propertyname,value so that I could get the entries in an easy way
}
var collection = _provider.GetCollection(userTableName);
var result = collection.Insert(new BsonDocument(elements.ToArray()));
return result.LastErrorMessage == null;
}
The IDictonary contains 4 keys named (Comparer,Count,Keys,Values), the key names and their count is fixed. The property name(s) for write to the db are stored as single objects inside of an object that is the value with the key "Keys" inside the Dictonary. The same applies to the values for the db, these are stored also inside an object that is an value with the key "Values". My problem is that I have no idea how to separate these objects. Here is an picture that shows the structure of the dictionary during the debug session.
http://i.stack.imgur.com/h4z7I.jpg
How I can access the objects inside of the objects that are stored as values?
EDIT:
Found now a way, is there a better one ?
var propnames = ((IEnumerable<object>) values["Keys"]).ToArray();
var propvalues = ((IEnumerable<object>)values["Values"]).ToArray();
dynamic test;
for (int i = 0; i < propnames.Count(); i++)
{
Type type = propvalues[i].GetType();
test = Convert.ChangeType(propvalues[i], type.UnderlyingSystemType);
//BsonValue bsonValue = test as BsonValue;
elements.Add(new BsonElement(propnames[i] as string,test ));
}
Related
My Xamarin app pulls data from an API and inserts that data into a SQLite table. The API currently has 9 tables defined, and as such there are 9 classes in my app that match those tables. I used the code snippet from this question's accepted answer:
Getting all types in a namespace via reflection
Below is my code, using the snippet from the answer and the foreach loop I'm trying to build that'll insert the data.
string nspace = "App.Tables";
var q = from t in Assembly.GetExecutingAssembly().GetTypes()
where t.IsClass && t.Namespace == nspace
select t.Name; // Getting list of classes as IEnumerable
var L = q.ToList(); // Converting to List
foreach (var name in L) // Inserts data for every class found
{
var response = await httpClient.Value.GetStringAsync("http://website.com/api/" + name + "s"); // Substitutes each class name into API url
var data = JsonConvert.DeserializeObject<List<TableName>>(response); // Deserializes into List
using (SQLiteConnection conn = new SQLiteConnection(App.DatabaseLocation)) // Opens database connection
{
conn.CreateTable<TableName>(); // Create table
conn.DeleteAll<TableName>(); // Delete all old data
conn.InsertAll(data); // Inserts new data
}
}
I don't know what TableName should be in order to get the correct class for each item on the list. For example: say the list contained the strings Table1, Table2, and Table3 - it got those strings from the App.Tables namespace which contains three separate classes called Table1, Table2, and Table3. When the first part of the code gets the list and stores it as the variable L, it should get the data for each "name" variable in L and then insert it into the matching table. How do I refer it to the table?
Before I would give my answer, I would like to tell you that I do not
recommend updating tables via reflection - tables should contain
logically distinct entities, so batch deleting and updating them is
kinda weird. This is one of those few occurrences where I would never
work around typing the updates of the tables one by one. But those are
just my two cents... Of course if I had a thousand tables my opinion
would not stand.
This kind of reflection also makes your code hard to follow and trace - think about how you will search for usages of the CreateTable<ExampleClass>() method? You will never trace it back - or only via great efforts - that you called it in this piece of code.
So to answer your question...
You first get the method group, then create a generic version of it based on the type. I think converting from Type to string is unnecessary for the part you're looking for, since you need to convert back to Type
using (SQLiteConnection conn = new SQLiteConnection(App.DatabaseLocation)) {
MethodInfo nonGenMethodCreate = typeof(SQLiteConnection).GetMethod("CreateTable");
MethodInfo nonGenMethodDeleteAll = typeof(SQLiteConnection).GetMethod("DeleteAll");
MethodInfo nonGenMethodInsertAll = typeof(SQLiteConnection).GetMethod("InsertAll");
foreach(Type t in Assembly.GetExecutingAssembly.GetTypes()) {
MethodInfo genMethodCreate = nonGenMethodCreate.MakeGenericMethod(t);
MethodInfo genMethodDeleteAll = nonGenMethodDeleteAll.MakeGenericMethod(t);
MethodInfo genMethodInsertAll = nonGenMethodInsertAll.MakeGenericMethod(t);
genMethodCreate.Invoke(conn, null);
genMethodDeleteAll.Invoke(conn, null);
genMethodInsertAll.Invoke(conn, new[] { data });
}
}
When you deal with JSON, it's really easy to make C# models. You either Paste special in Visual Studio, or you use one of the many available tools online.
ElasticSearch responses obviously are JSON, meaning, if you can get the responding JSON, you're good to go. However, if you just have a connection-string and simply want to "map" all the ElasticSearch objects into your C# code - how do you do it?
My question:
Is there a way to see all fields/data in an ElasticSearch instance, and then easily get the JSON, so you can get strongly typed models?
You can query elasticsearch for mappings. Mapping will contain all information you need to build model in C# (but you will still have to build it by hand I think). Example using database from your previous question:
var settings = new ConnectionSettings(new Uri("http://distribution.virk.dk/cvr-permanent"));
var client = new ElasticClient(settings);
// get mappings for all indexes and types
var mappings = client.GetMapping<JObject>(c => c.AllIndices().AllTypes());
foreach (var indexMapping in mappings.Indices) {
Console.WriteLine($"Index {indexMapping.Key.Name}"); // index name
foreach (var typeMapping in indexMapping.Value.Mappings) {
Console.WriteLine($"Type {typeMapping.Key.Name}"); // type name
foreach (var property in typeMapping.Value.Properties) {
// property name and type. There might be more useful info, check other properties of `typeMapping`
Console.WriteLine(property.Key.Name + ": " + property.Value.Type);
// some properties are themselves objects, so you need to go deeper
var subProperties = (property.Value as ObjectProperty)?.Properties;
if (subProperties != null) {
// here you can build recursive function to get also sub-properties
}
}
}
}
I have appSourceInfoModel taken from Database, now i am passing ViewModel i.e. reviewerAppsBacklogViewModel and if reviewerAppsBacklogViewModel and appSourceInfoModel are same then do not update database if there are changes then Update. I am doing, first assigning to variable var DBappSourceInfoModel = appSourceInfoModel; then I assigning some values to appSourceInfoModel then comparing the initially saved model DBappSourceInfoModel and appSourceInfoModel. But, assigning some values to appSourceInfoModel also change values in the initially saved model DBappSourceInfoModel. All of the code can be found below.
AppSourceInfo appSourceInfoModel = _appSourceInfoRepository.Get(a => a.Review.ReviewId == reviewId);
var DBappSourceInfoModel = appSourceInfoModel; //Initially save Model in var
appSourceInfoModel.Cost = reviewerAppsBacklogViewModel.Cost;
appSourceInfoModel.InProgress = true;
appSourceInfoModel.PegiRating = reviewerAppsBacklogViewModel.PegiRating;
appSourceInfoModel.Rating = reviewerAppsBacklogViewModel.AverageUserReviewsRating;
appSourceInfoModel.DownloadCounter = reviewerAppsBacklogViewModel.NoofDownloadsFromSource;
appSourceInfoModel.ReviewCounter = reviewerAppsBacklogViewModel.NoofReviewOfSource;
appSourceInfoModel.StoreCategory = reviewerAppsBacklogViewModel.StoreCategory;
var IsAppSourceInfoModelChanged = !DBappSourceInfoModel.Equals(appSourceInfoModel);
if (IsAppSourceInfoModelChanged)
{
_appSourceInfoRepository.Update(appSourceInfoModel);
}
I have Solved it using this simple Code in My Model i.e. AppSourceInfo
public object Clone()
{
return this.MemberwiseClone();
}
and change the following code
var DBappSourceInfoModel = appSourceInfoModel; //Initially save Model in var
to
var DBappSourceInfoModel = (AppSourceInfo) appSourceInfoModel.Clone();
You need to perform a Copy (shallow probably sufficient)
var DBappSourceInfoModel = appSourceInfoModel;
Is simply creating a reference to the same object. Implement ICloneable on the DBappSourceInfoModel then use Clone method,
Your Clone method needs to copy all the info to the new Object, also performing Deep Copies on internal references if needed,
This will copy all the details to the other object and create two separate objects,
look here for reference:
https://msdn.microsoft.com/en-us/library/system.icloneable%28v=vs.110%29.aspx
EDIT
Just to be clear, you also need to use the IComparable interface to define how the objects are compared for equality,
https://msdn.microsoft.com/en-us/library/system.icomparable%28v=vs.110%29.aspx
Is it possible in Entity Framework to figure out the actual changes/diff which entity framework is going to make in the database?
Consider an example, let say that some rows are already present in the database and we try to add them again. Since the rows are already present, the actual changes/diff made in the database is null. Similarly, if I try to 10 rows, out of which only 3 got updated, then I want only those 3.
I was trying using DbContext.ChangeTracker to achieve the same but it looks like that it returns all the rows which we are trying to add/update/delete irrespective of whether some of them are already there in the database. Can someone confirm this behavior as well?
I used the following code in my base repository to get a dictionary of modified property names and the old DB values. The new values can be get easily by the TModel object itself.
private Dictionary<string, object> GetModifiedProperties(TModel model)
{
var entry = Context.Entry(model);
// entry is detached.
// set entry to database entry and its CurrentValues to model values
if (entry.State == EntityState.Detached)
{
object key = model.GetType().GetProperty("Id").GetValue(model);
if (key == null)
{
throw new InvalidOperationException("The Entity you desire to update does not contain an Id value.");
}
var dbModel = Context.Set<TModel>().Find(key);
var dbEntry = Context.Entry(dbModel);
dbEntry.CurrentValues.SetValues(model);
entry = dbEntry;
//entry.State = EntityState.Modified;
}
var modifiedProps = new Dictionary<string, object>();
foreach (var propertyName in entry.CurrentValues.PropertyNames)
{
// copy only changed values to dict
var prop = entry.Property(propertyName);
if (prop.IsModified)
{
modifiedProps.Add(propertyName, prop.OriginalValue);
}
}
return modifiedProps;
}
Sadly I found no elegant way to get the Key property. But "Id" worked for me. Only the changed properties should appear in the dictionary. Not exactly what you want but something to work with.
Edit: I use the Unit of Work pattern for my DAL. Every repository derives from my base repository, where this code comes from. The update method triggers the GetModifiedProperties() method.
You can than write an update method like that:
UnitOfWork.CutomerRepository.Update(Customer updated, out Dictionary<string, object> changedProps);
I'm writing a application where the user can write json-code and store that json code with an Id and a Collection. In other words, they specify an Id, a Collection (string; [a-zA-Z0-9]) and a Data (json, can be anything that is valid json).
Up til now I've been using RavenDb for this, cause I thought a document-database would be perfect, but I've had some problems with querying.
One of the objects that needs to be stored and queried is the following:
{
"network": "some_network",
"names": ["name1","name2"],
"data": {"values":[],"keys":[]}
}
This object should be stored with some Id that is either specified, or auto-generated (if null is given), and a Collection (must always be specified), and then I need to be able to query it based on Collection, network and a single name.
For instance, I have the code query('users', '{"network":"some_network","names":"name1"}'), and I need that code to return this object (and any other object that matches it).
Also, I'm ok with changing database, but the database needs to be able to run in-process (self-hosted), and to be able to run without admin-rights without installation (in other words, it can't bind to hostname/ip like wcf does).
How can I achieve something like this?
I found the answer to this:
public string Query(string dynIndexName, string query)
{
using (var session = store.OpenSession())
{
var q = new IndexQuery();
q.Query = query;
var result = session.Advanced.DatabaseCommands.Query("dynamic/" + dynIndexName, q, new string[0]);
return "[" + String.Join(",", result.Results.Select(r => r.ToString())) + "]";
}
}
Before calling the Query-method I convert the json-query-object into a Lucene-query that looks like this: (network:"some_network" AND names:"name1"), and use that as a query-parameter to the database. The whole class for storing and retrieving can be found here: https://github.com/Alxandr/RunJS/blob/master/src/AddIns/Storage/StorageMbro.cs