Xamarin sqlite-net-pcl accessing values of database internal - c#

I'm using Visual Studio 2017, new to SQLite and can't get my head behind how I get to access the values saved in the database and get it back to the elements of the class.
public class MyObject
{
[PrimaryKey, AutoIncrement]
public int IndexNumber
{get;set;}
[MaxLength(20)]
public int SomeID
{get;set;}
[MaxLength(70)]
public string SomeName
{get; set;}
[MaxLength(25)]
public string Telephone
{get; set;}
public DateTime someTime
{get; set;}
//...some more data
}
public class MyDB
{
readonly SQLiteAsyncConnection database;
public MyDB (string dbPath);
database.CreateTableAsync<MyObject>().Wait();
public Task<List<MyObject>> GetMyObjectAsync()
{
return database.Table<MyObject>().ToListAsync();
}
public Task<MyObject> GetSingleObjectAsync(int ind)
{
return database.Table<MyObject>().Where(i => i.IndexNumber == ind).FirstOrDefaultAsync();
}
public Task<int> SaveMyObjectAsync(MyObject object)
{
if (object.IndexNumber == 0)
{
return database.InsertAsync(object)
}
else
{
return database.UpdateAsync(object);
}
}
public Task<int> DeleteMyObjectAsync(MyObject object)
{
return database.DeleteAsync(object);
}
}
Inputting data through the .xaml pages works without any problems so far, selecting the object in ListView works as well.
The problem now is that I just can't seem to find a proper way to convert the returned Task back to an object to update some of those values with data only supplied through a HTTP response which itself does not always supply all the data for the datatable, e.g. only the ID and a code if it was successful in the first response.
It then needs other data from the object and again delivers values for different elements of the object which is why I'd like to know if there was some method to get a row of data back to a temporary object to update it in the database, remove it if needed (canceled through the HTTP response) or modify it.

Your problem is all about not using await keyword. Whenever you call asynchronous method with no await keyword you are doing it wrong :) I strongly recommend you to read James Montemagno blog post about it here.
Here is solution of your problems.
public class MyDB
{
readonly SQLiteAsyncConnection database;
public MyDB(string dbPath)
{
database = new SQLiteAsyncConnection(dbPath);
}
public async Task CreteMyDb()
{
await database.CreateTableAsync<MyObject>();
}
public async Task<List<MyObject>> GetMyObjectsAsync()
{
return await database.Table<MyObject>().ToListAsync();
}
public async Task<MyObject> GetSingleObjectAsync(int ind)
{
return await database.Table<MyObject>().Where(i => i.IndexNumber == ind).FirstOrDefaultAsync();
}
public async Task<int> SaveMyObjectAsync(MyObject myObject)
{
if (myObject.IndexNumber == 0)
{
return await database.InsertAsync(myObject);
}
else
{
return await database.UpdateAsync(myObject);
}
}
public async Task<int> DeleteMyObjectAsync(MyObject myObject)
{
return await database.DeleteAsync(myObject);
}
}
And example usage of methods.
await this.myDb.CreteMyDb();
await this.myDb.SaveMyObjectAsync(new MyObject()
{
SomeID = 1,
SomeName = "Adam",
someTime = DateTime.Now,
Telephone = "53535353"
});
var list = await this.myDb.GetMyObjectAsync();
Let me know if it helped!

Related

How to cast a model of T type to 'System.Dynamic.ExpandoObject' in C#? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed last year.
Improve this question
I am trying to add some parameters in the class Job.cs
namespace Test
{
public class Job
{
public int Id { get; set; }
public int JobId { get; set; }
public int JobPropertyType { get; set; }
public string JobValue { get; set; }
}
}
I am using Dapper for Inserting Data in the tables.
Repository.cs
public async Task<T> Add(T entity)
{
using (var connection = await _connectionFactory.GetConnectionAsync())
{
return await connection.InsertAsync<T>(entity);
}
}
I have used DapperMapper for mapping table and data.
Mapper.cs
public class JobMapper: ClassMapper<Job>
{
public JobMapper()
{
Schema("Job");
Table("Job");
Map(m => m.JobId).Column("JobId");
Map(m => m.JobPropertyType).Column("JobPropertyType");
Map(m => m.JobValue).Column("JobValue");
}
}
Here is the JobService.cs
public async Task<Job> InsertJob(int jobId, int jobPropertyType, string jobValue)
{
var job = new Job
{
JobId = jobId,
JobPropertyType = jobPropertyType,
JobValue = jobValue
};
return await this.Repository.Add(job);
}
Another service sending data
public async Task AddJob(int jobId, string snapshot)
{
if (!string.IsNullOrEmpty(snapshot))
{
await _jobService.InsertJob(jobId, (int)JobPropertiesEnum.Snapshot, snapshot);
}
When I am trying to Insert data here, I am getting this exception:
Message=Cannot implicitly convert type 'System.Dynamic.ExpandoObject' to 'Test.Job'. at the time of Inserting (InsertyAsync() in the Repository)
How can I cast it into Dynamic.ExpandoObject?
I assume you are using Dapper-Extensions from here: https://github.com/tmsmith/Dapper-Extensions/tree/master/DapperExtensions
InsertAsync returns a Task<dynamic>, dynamic is an ExpandoObject, so your problem arises when you try to get the return value. The return value is the key of the inserted entity.
You can change your code to something like this (I didn't have time to test it):
public async Task<T> Add(T entity)
{
using (var connection = await _connectionFactory.GetConnectionAsync())
{
var result = await connection.InsertAsync<T>(entity);
entity.Id = (int) result;
return entity;
}
}

ASP.NET Web API possible deserialization issue while using flurl

I have a ASP.NET(C#, .NET 4.6.1) Web-Api-GET function which returns a complex object instance and is of generic type. Here is the return type definition (Note that the classes are much expansive in reality).
public class FileProcessInstance
{
public FileProcessInstance()
{ }
//ID that identifies file by primary key of log table
public int FileLogID;
//File name without path as received
public string OriginialFileName;
//Path with file name where file can be physically accessed
public string FileSharePath;
}
public class CommonStatusPayload<T> : CommonStatus
{
public CommonStatusPayload() : base(false)
{
Payload = default(T);
}
public CommonStatusPayload(T payload, bool status)
: base(status)
{
Payload = payload;
}
public virtual T Payload { get; private set; }
}
public class CommonStatus
{
public CommonStatus() : this(false)
{
}
public CommonStatus(bool status)
{
Status = status;
}
public bool Status { get; set; }
}
Now my web api looks like this:
[HttpGet]
public CommonStatusPayload<List<FileProcessInstance>> GetFilesForProcessing()
{
List<FileProcessInstance> lst = new List<FileProcessInstance>() { new FileProcessInstance() { FileLogID = 1, FileSharePath = #"\\d\s", OriginialFileName = "d.txt" } };
CommonStatusPayload<List<FileProcessInstance>> cs = new CommonStatusPayload<List<FileProcessInstance>>(lst, true);
return cs;
}
The issue is, a call to this api from C# code would receive null as payload, while Postman request does receive proper payload.
Now my client code looks like this:
static void Main(string[] args)
{
var lst = GetFilesForProcessing();
}
private static List<FileProcessInstance> GetFilesForProcessing()
{
List<FileProcessInstance> lst = new List<FileProcessInstance>();
try
{
Task<CommonStatusPayload<List<FileProcessInstance>>> task = GetFilesForProcessingFromAPI();
task.Wait();
if (task.Result.Payload != null)
lst.AddRange(task.Result.Payload);
}
catch (Exception ex)
{
}
return lst;
}
private static async Task<CommonStatusPayload<List<FileProcessInstance>>> GetFilesForProcessingFromAPI()
{
return await "http://localhost:10748/api/values/GetFilesForProcessing".ToString()
.GetAsync().ReceiveJson<CommonStatusPayload<List<FileProcessInstance>>>();
}
I have observed that the return payload works if it were to be a a) list by itslef b) a local instance of CommonStatusPayload<List<FileProcessInstance>>. This makes me believe that there is a possible deserialization issue, when the result is handed over to C# code from web-api. A fiddler check for the same request turns out to be just fine, just that C# client would not receive proper result.
Any guess as to what could be the underlying reason for payload being null?
I found the root cause of this issue. The private setter for Payload within CommonStatusPayload class is causing the deserialization to fail. Although for the intended behavior, i wanted the payload to be set only via constructor/method always to be associated with a relative status, at-least this change allows me to continue.
I did find some other questions here, related to JSON.NET with protected setters having same issues.

The source IQueryable doesn't implement IDbAsyncEnumerable when trying to mock

I am trying to test a bit of code I have:
public async Task<Sortation> SaveAsync(Sortation sortation)
{
if (sortation.Id == 0)
{
var sortations = await ListAsync(sortation.CategoryId);
sortation.Order = sortations.Count;
_sortationService.Create(sortation);
}
else
{
_sortationService.Update(sortation);
}
await _sortationService.SaveChangesAsync();
return sortation;
}
The ListAsync method is causing me an issue.
I set up my test like this:
[Test]
public async Task ShouldHaveOrderOfZero()
{
// Assemble
const string categoryId = "cameras";
var services = SortationContext.GivenServices();
var sortationProvider = services.WhenGetSortationProvider();
var sortations = new List<Sortation>();
var sortation = new Sortation { CategoryId = categoryId };
services.MockSortationService.Setup(x => x.List()).Returns(sortations.AsQueryable);
// Act
await sortationProvider.SaveAsync(sortation);
// Assert
sortation.Order.Should().Be(0);
}
And when I run this, I get this error:
Message: System.InvalidOperationException : The source IQueryable doesn't implement IDbAsyncEnumerable. Only sources that implement IDbAsyncEnumerable can be used for Entity Framework asynchronous operations.
According to this: Only sources that implement IAsyncEnumerable can be used for Entity Framework asynchronous operations I need to add EF to my UnitTest project, which I did.
But the error still persists.
The ListAsync method looks like this:
public async Task<List<Sortation>> ListAsync(string categoryId, params string[] includes) =>
await _sortationService.List(includes).Where(m => m.CategoryId.Equals(categoryId)).ToListAsync();
Does anyone know how I can stop this error from happening?
In my case the exception was caused by using the wrong ToListAsync extension.
It came from:
using System.Data.Entity;
instead of
using Microsoft.EntityFrameworkCore;
Changing the namespace fixed the error.
Don't know if question is still actual, but still. I agree with Mark's comment, however here is an example, that works for me. I added some reasonable stub implementation for mentioned class, because there are not enouch details in question. I can be wrong in my assumptions:
[Test]
public async Task ShouldHaveOrderOfZero()
{
// Assemble
const string categoryId = "cameras";
var services = SortationContext.GivenServices();
var sortationProvider = services.WhenGetSortationProvider();
var sortations = new List<Sortation>();
var sortation = new Sortation { CategoryId = categoryId };
// the key moq configuration here
services.MockSortationService.Setup(x => x.ListAsync(It.IsAny<string>())).Returns(Task.FromResult(sortations));
// Act
await sortationProvider.SaveAsync(sortation);
// Assert
sortation.Order.Should().Be(0);
}
public class SortationProvider
{
private SortationService _sortationService;
public SortationProvider()
{
_sortationService = new SortationService();
}
public async Task<Sortation> SaveAsync(Sortation sortation)
{
if (sortation.Id == 0)
{
var sortations = await ListAsync(sortation.CategoryId);
sortation.Order = sortations.Count;
_sortationService.Create(sortation);
}
else
{
_sortationService.Update(sortation);
}
await _sortationService.SaveChangesAsync();
return sortation;
}
// should be virtual
public virtual async Task<List<Sortation>> ListAsync(string categoryId, params string[] includes) =>
await _sortationService.List(includes).Where(m => m.CategoryId.Equals(categoryId)).ToListAsync();
}
public class SortationContext
{
public static Services GivenServices()
{
return new Services();
}
}
public class Services
{
public Services()
{
MockSortationService = new Mock<SortationProvider>();
}
public SortationProvider WhenGetSortationProvider()
{
return MockSortationService.Object;
}
public Mock<SortationProvider> MockSortationService { get; set; }
}
internal class SortationService
{
public void Create(Sortation sortation)
{
}
public void Update(Sortation sortation)
{
}
public Task SaveChangesAsync()
{
return Task.CompletedTask;
}
public DbSet<Sortation> List(string[] includes)
{
throw new NotImplementedException();
}
}
public class Sortation
{
public string CategoryId { get; set; }
public int Id { get; set; }
public int Order { get; set; }
}
The main change is in line that contains Setup method. I made ListAsync method virtual also. The main assumption is that List(string[] includes) method returns DbSet<Sortation>. Hope it helps.

Serializing Model using NewtonSoft in WPF Application

I am trying to serialize my model each second and push it to a server. I have set up a periodic task which executes each second. I call SendNewMessage to execute the push.
The first method call to SendNewMessage() which is called from the constructor runs fine with no exceptions or issues.
When the async task tries to call the SendNewMessage I get an exception and my application shuts down. It is the NewtonSoft code:
String PushModelToServer = JsonConvert.SerializeObject(this, jss); Which fails
Managed Debugging Assistant 'FatalExecutionEngineError' has detected a problem in
'C:\Users\snovva\Source\Workspaces\HMI\HMI.ViSoft\bin\x86\Debug\HMI.ViSoft.vshost.exe'.
Additional information: The runtime has encountered a fatal error. The address of the error was at 0x71041771, on thread 0x2788. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.
public class Model : ModelBase
{
public Model ()
{
PeriodicTask.Run(() =>
{
SendNewMessage();
},
TimeSpan.FromSeconds(1));
SendNewMessage();
}
public void SendNewMessage()
{
// Send the message
JsonSerializerSettings jss = new JsonSerializerSettings();
jss.Formatting = Newtonsoft.Json.Formatting.Indented;
String PushModelToServer = JsonConvert.SerializeObject(this, jss);
sendMessage(System.Text.Encoding.Unicode.GetBytes(PushModelToServer));
}
}
public class PeriodicTask
{
public static async Task Run(Action action, TimeSpan period, CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
await Task.Delay(period, cancellationToken);
if (!cancellationToken.IsCancellationRequested)
action();
}
}
public static Task Run(Action action, TimeSpan period)
{
return Run(action, period, CancellationToken.None);
}
}
More Info As requested:
The call on line 10 in the constructor runs. The serialization works the first time. Since the data in the model is changing I am pushing this model every second to update server. It is the async call which fails. As time passes the data in the model will change.
You can use [IgnoreDataMember] to avoid serializing properties that should not be included.
The code below works in my application, and should hopefully help you arrive at a solution for your app.
I am hoping that the code you show above is a snippet of your real code because there are some potential issues with the 1 second timer, re-entrancy, etc. Instead of doing this timer in the Model constructor, consider moving it to another function/class and setting up the timer/calls from an additional call you setup later...again, just some suggestions on arriving at a good pattern. Do more research here...
Here is how I get my data, what you want in your PushModelToServer:
public class BackupData
{
public List<Vehicles> Vehicles { get; private set; }
public List<FuelStops> FuelStops { get; private set; }
public BackupData(List<Vehicles> vehicles, List<FuelStops> fuelStops)
{
Vehicles = vehicles;
FuelStops = fuelStops;
}
public string ToJson(Formatting formatting = Formatting.None)
{
var json = JsonConvert.SerializeObject(this, formatting);
return json;
}
public static BackupData FromJson(string jsonBackupData)
{
var data = JsonConvert.DeserializeObject<BackupData>(jsonBackupData);
return data;
}
}
Here is a snippet of one of my classes:
[DebuggerDisplay("{VehicleName}")]
public class Vehicles : IComparable<Vehicles>, INotifyPropertyChanged
{
private string id;
public string Id
{
get { return id; }
set
{
if (id != value) { id = value; NotifyPropertyChanged(); }
}
}
private string vehicleName;
public string VehicleName
{
get { return vehicleName; }
set
{
if (vehicleName != value) { vehicleName = value; NotifyPropertyChanged(); }
}
}
public override string ToString()
{
return VehicleName;
}
[IgnoreDataMember]
public UpdateState UpdateState { get; set; }
....
And here is how I get the data so I can use it anywhere I want:
#if WINDOWS_PHONE_APP
private void OnExecuteBackup(SettingsPage obj)
{
#else
private async Task<bool> OnExecuteBackup(SettingsPage obj)
{
#endif
var backupData = App.JournalModel.GetBackupData().ToJson(Formatting.Indented);
...
await SaveBackupFile(file, backupData);
...
public class JournalModel
{
...
public BackupData GetBackupData()
{
var data = new BackupData(Vehicles.ToList(), FuelStops.ToList());
return data;
}
...
Good luck with your project.
Well there must be something the the class You're trying to serialize, that makes the serializer go crazy. Maybe instead of serializing 'this' You should try serializing an actual 'DataObject' - something that can be serialized, and doesn't contain references to Timers, tasks, ect.. ?

Implementing simple cache in Windows Phone 8.1 Class Library

I am trying to implement a simple caching mechanism in a windows phone 8.1 API that I am creating. I have chosen a Windows Phone Portable Class Library template in visual studio.
Refrence : http://channel9.msdn.com/Series/Windows-Phone-8-1-Development-for-Absolute-Beginners/Part-22-Storing-and-Retrieving-Serialized-Data
The cache class looks something like this,
[DataContract]
class cache
{
private const string JSONFILENAME = "data.json";
[DataMember]
Dictionary<Int32, item> cDictionary;
[DataMember]
int _maxSize;
public int MaxSize
{
get { return _maxSize; }
set { _maxSize = value; }
}
public cache(int maxSize){
cDictionary = new Dictionary<int, item>();
_maxSize = maxSize;
}
public void push(Int32 id, item obj)
{
if (!cDictionary.ContainsKey(id)) {
cDictionary.Add(id, obj);
}
}
internal static async Task<cache> Load()
{
cache obj = null;
try
{
var jsonSerializer = new DataContractJsonSerializer(typeof(cache));
using (var myStream = await ApplicationData.Current.LocalFolder.OpenStreamForReadAsync(JSONFILENAME))
{
obj = (cache)jsonSerializer.ReadObject(myStream);
}
}
catch (FileNotFoundException)
{
obj = null;
}
return obj;
}
internal static async void Save(cache obj)
{
var serializer = new DataContractJsonSerializer(typeof(cache));
using (var stream = await ApplicationData.Current.LocalFolder.OpenStreamForWriteAsync(
JSONFILENAME,
CreationCollisionOption.ReplaceExisting))
{
serializer.WriteObject(stream, obj);
}
}}
The item class whose objects go into the dictionary looks like this,
[DataContract]
class item
{
[DataMember]
string _fName;
public string FName
{
get { return _fName; }
set { _fName = value; }
}
[DataMember]
string _lName;
public string LName
{
get { return _lName; }
set { _lName = value; }
}
[DataMember]
int _id;
public int Id
{
get { return _id; }
set { _id = value; }
}
public item(int id, string fName, string lName)
{
this.Id = id;
this.FName = fName;
this.LName = lName;
}
}
The idea is : The end user creates an instance of the api and calls a method doSomething(). The method first looks in the cache (not shown in the example) if found, returns the Item object back, or else, gets the item object from a web service(not shown) and then push it to cache.
public class api
{
cache tCache;
string apiKey;
public laas(string apiKey)
{
this.apiKey = apiKey;
this.tCache = new cache(100);
}
public async void Initialize(api obj)
{
//If cache exists
obj.tCache = await cache.Load();
if (obj.tCache == null)
{
obj.tCache = new cache(100);
}
}
public void doSomething(string id)
{
tCache.push(id.GetHashCode(),new item(1,"xxxx","xxx"));
cache.Save(tCache);
}
}
I wanted to initialize/load the cache in the constructor of the api class, but since ApplicationData.Current.LocalFolder provide only async methods to read and write data from persistent storage, I created a separate static async class Initiialize() that would load the cache, since making an async constructor makes no sense.
Problem: the statement tCache.push(id.GetHashCode(),new item(1,"xxxx","xxx")); in the doSomething() throws null reference exceptions. This could possibilly be happening because the tCache hasn't been loaded/initialized yet due to the async operation.
I had tried obj.tCache = await cache.Load().Result to wait for the loading to complete, but that hangs my application. (http://msdn.microsoft.com/en-us/magazine/jj991977.aspx)
Could you please point me in the right directions here? Is my diagnonis right? Is there a better way to do it? Any pointer is appreciated.
Thanks!
What is probably happening is that you're calling Initialize but not awaiting it, because it is async void.
What you need to do is change:
public async void Initialize(api obj)
To:
public async Task Initialize(api obj)
Then, you'll need to await Initialize(obj) which will ensure that caches completion before use.
Note that async void is ment only for top level event handlers and shouldn't be used otherwise.
Also, the reason Task.Result hangs your application is because it is causing a deadlock, which is related to the way async marshals your synchronization context between calls.

Categories