I am using DeleteDocumentAsync as per below code.
public static void DeleteErrorLog(List<string> LogID, string collectionName)
{
FeedOptions queryOptions = new FeedOptions { EnableCrossPartitionQuery = true };
try
{
//getting resource id for a document with given logid
var db = client.CreateDatabaseQuery().Where(x => x.Id == databaseName).ToList().First();
var coll = client.CreateDocumentCollectionQuery(db.SelfLink).Where(x => x.Id == collectionName).ToList().First();
var docs = client.CreateDocumentQuery(coll.SelfLink, queryOptions).Where(x => x.Id == LogID[0]).AsEnumerable().Single();
var collectionUri = UriFactory.CreateDocumentUri(databaseName, collectionName, docs.ResourceId);
client.DeleteDocumentAsync(collectionUri);
}
catch (Exception) { throw; }
}
Every value is populating correctly and I am getting the document that I need to delete still unable to delete it? Any help is greatly appreciated
You are probably missing the PartitionKey for the delete operation:
var documentUri = UriFactory.CreateDocumentUri(databaseName, collectionName, LogID[0]);
client.DeleteDocumentAsync(documentUri, new RequestOptions(){PartitionKey=new PartitionKey(LogID[0])}).GetAwaiter().GetResult();
Also, if you already know the Id, which in your case is LogID[0], you don't need the Query.
You're not awaiting client.DeleteDocumentAsync, which means your catch will not catch exceptions that occur in the Task that's created - it will silently fail.
My guess is that due to this, there is an exception being thrown in DeleteDocumentAsync that's not subsequently caught where expected.
Ideally, this method would be re-written to use async/await, then your try catch will pick up any exceptions being thrown:
public static async Task DeleteErrorLog(List<string> LogID, string collectionName)
{
...
await client.DeleteDocumentAsync(collectionUri);
...
}
You'll have to make sure that the code calling this method also uses await.
Related
I'm using Realm for .NET v10.1.3, and I've got a method that deletes some objects. Pulling from the documentation that indicates that Contains is supported, I have the following snippet:
var results = realm.All<DeviceEventEntity>()
.Where(entity => ids.Contains(entity.Id));
realm.RemoveRange(results);
But when realm.RemoveRange(results) is executed, Realm throws a System.NotSupportedException. What am I doing wrong here? Or does Realm not support Contains?
Here's the stacktrace:
System.NotSupportedException
The method 'Contains' is not supported
at Realms.RealmResultsVisitor.VisitMethodCall(MethodCallExpression node) in C:\jenkins\workspace\realm_realm-dotnet_PR-2362#2\Realm\Realm\Linq\RealmResultsVisitor.cs:line 378
at Realms.RealmResultsVisitor.VisitMethodCall(MethodCallExpression node) in C:\jenkins\workspace\realm_realm-dotnet_PR-2362#2\Realm\Realm\Linq\RealmResultsVisitor.cs:line 164
at Realms.RealmResults`1.CreateHandle() in C:\jenkins\workspace\realm_realm-dotnet_PR-2362#2\Realm\Realm\Linq\RealmResults.cs:line 65
at System.Lazy`1.CreateValue()
at System.Lazy`1.LazyInitValue()
at Realms.RealmResults`1.get_ResultsHandle() in C:\jenkins\workspace\realm_realm-dotnet_PR-2362#2\Realm\Realm\Linq\RealmResults.cs:line 30
at Realms.Realm.RemoveRange[T](IQueryable`1 range) in C:\jenkins\workspace\realm_realm-dotnet_PR-2362#2\Realm\Realm\Realm.cs:line 1279
at DocLink.Client.Storage.Service.Event.DeviceEventService.<>c__DisplayClass2_0.<DeleteEvents>b__0() in
Here's a more complete example:
public Task DeleteEvents(List<ObjectId> ids) {
return Task.Run(() => {
using (var realm = GetRealm()) {
using (var transaction = realm.BeginWrite()) {
try {
var results = realm.All<DeviceEventEntity>().Where(entity => ids.Contains(entity.Id));
realm.RemoveRange(results);
transaction.Commit();
}
catch (Exception exception) {
transaction.Rollback();
throw new ServiceException("Unable to delete events. Transaction has been rolled back.", exception);
}
}
}
});
}
Also, it seems a little odd that the library is referencing files like this C:\jenkins\workspace\realm_realm-dotnet_PR-2362#2\Realm\Realm\Linq\RealmResultsVisitor.cs. This is not anything that's on my system, the library is pulled in through NuGet.
Docs say you need to use Filter when you encounter a NotSupportedException. Read the comments on the method for a link to the NSPredicate cheat sheet, there is quite a lot you can do with it :)
Update to question. First and foremost, thank you to all who participated and help point me in the right direction. The final answer ended up being a combination of a couple of things, but in short it was this previous post that ended up solving the issue.
The current version of Realm has support for Mongo ObjectId, however, using ObjectId in the Filter() method didn't really work. So the fix was to end up using a string as the PK but use ObjectId in the DTO -- converting to ObjectId on the way out, and ToString() on the way into Realm.
public static class IQueryableExtensions {
public static IQueryable<T> In<T>(this IQueryable<T> source, string propertyName, IList<ObjectId> objList)
where T : RealmObject {
var query = string.Join(" OR ", objList.Select(i => $"{propertyName} == '{i.ToString()}'"));
var results = source.Filter(query);
return results;
}
}
My code utilizing the extension
public Task DeleteEvents(List<ObjectId> ids) {
return Task.Run(() => {
using (var realm = GetRealm())
{
using (var transaction = realm.BeginWrite())
{
try {
// In order to support this with the current version of Realm we had to write an extension In()
// that explodes the list into a Filter() expression of OR comparisons. This also required us
// to use string as the underlying PK type instead of ObjectId. In this way, our domain object
// still expects ObjectId, so we ToString() on the way into realm and ObjectId.Parse() on the
// way out to our DTO.
var results = realm.All<DeviceEventEntity>().In("Id", ids);
realm.RemoveRange(results);
transaction.Commit();
}
catch (Exception exception)
{
transaction.Rollback();
throw new ServiceException("Unable to delete events. Transaction has been rolled back.", exception);
}
}
}
});
}
I am using neo4jclient graph database with .net core API. I have to add the health checks. I have created my own health check using Ihealthcheck interface. below is my healthcheck class
public class DatabaseHealthCheck : IHealthCheck
{
public DatabaseHealthCheck(IGraphClient graphClient)
{
_graphClient = graphClient;
}
private readonly IGraphClient _graphClient;
public async Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context,
CancellationToken cancellationToken = default(CancellationToken))
{
try
{
var result = await _graphClient.Cypher.Match(#"show databases")
.Return((n) => n.As<DatabaseDetail>()).ResultsAsync;
foreach (var res in result)
{
if (res.currentStatus == "Online")
{
return await Task.FromResult(
HealthCheckResult.Healthy("Healthy"));
}
}
}
catch (Exception ex)
{
return new HealthCheckResult(status: context.Registration.FailureStatus, exception: ex);
}
return HealthCheckResult.Healthy();
// return await Task.FromResult(
// new HealthCheckResult(context.Registration.FailureStatus,
// "Unhealthy"));
}
}
With this health check I want to get the database details and then check the status of database weather it is online or not but I am getting the below error
Neo4j returned a valid response, however Neo4jClient was unable to deserialize into the object structure you supplied.
Can anyone help me ?
The query you're writing will not return anything, what you're actually executing is:
MATCH (show databases)
RETURN n
You can see this if you change your code to look like this:
var query = _graphClient.Cypher.Match(#"show databases")
.Return((n) => n.As<string>());
var text = query.Query.DebugQueryText;
var result = await query.ResultsAsync;
If you put a breakpoint in so you can see what the text variable will be you'll be able to see it.
Now! I can't think how to get what you want when you're using the GraphClient - it might be possible with the BoltGraphClient - but the error you're getting implies you're using the former.
IF you were on the BoltGraphClient, you could access the Driver and execute:
var session = ((BoltGraphClient)_graphClient).Driver.AsyncSession(d => d.WithDatabase("system"));
var cursor = await session.RunAsync("SHOW DATABASES");
while (await cursor.FetchAsync())
{
var name = cursor.Current.Values["name"].As<string>();
var status = cursor.Current.Values["currentStatus"].As<string>();
Console.WriteLine($"{name} is {status.ToUpperInvariant()}");
}
I don't know any other work around with the http GraphClient - it would need to be added to the client. In theory - it's not a complex PR to do if you wanted to.
I'm building a game in Unity version 2019.4.1f1 (LTS) and i'm using Firebase Firestore database.
Basically when I try to fetch the user from the database, specifically when i'm calling GetSnapshotAsync(), it gets stuck.
The hierarchy is as follows:
StartState calls FetchUserState which calls DBGetObjectState which communicates with DatabaseManager (DatabaseManager contains the line where GetSnapshotAsync() gets called).
Would be really nice if someone could help me figure out this problem.
Thank you for helping!
class FetchUserState
//fetch user by userId
await stateManager.PushTempState(new DBGetObjectState<T>(StringConstants.DB_USERS_COLLECTION, //("Users")
field: "UserId", fieldEqualTo: _userId, withLoading: false));
class DBGetObjectState
Log("Getting Documents");
var documents = await DatabaseManager.GetDocuments<T>(_path, _limit, _orderBy, _orderByDescending, _field, _fieldEqualTo);
Log("Got something, checking..."); // doesn't get here
class DatabaseManager
public static async Task<Collection<T>> GetDocuments<T>(string path, int limit = -1,
string orderBy = null, string orderByDescending = null, string field = null, object fieldEqualTo = null)
{
var collectionRef = DBUtills.GetCollectionRef(path);
Query query = collectionRef;
if (field != null && fieldEqualTo != null)
query = query.WhereEqualTo(field, fieldEqualTo);
if (orderBy != null)
query = query.OrderBy(orderBy);
if (orderByDescending != null)
query = query.OrderByDescending(orderByDescending);
if (limit >= 0)
query = query.Limit(limit);
Debug.Log("Snapshotting!");
QuerySnapshot collectionSnapshot = await query.GetSnapshotAsync();
Debug.Log("got a snapshot, checking..."); // doesn't get here
//....
}
Thanks to anyone who tried to help, apparently it was a plugin that I used for handling tasks, I should've checked it first before even asking the question.
Anyways, if someone still experiences an issue, #derHugo's answer was definitely a solution, instead of awaiting the task, simply use ContinueWithOnMainThread() to create a callback that will be called after the task is finished, like that:
query.GetSnapshotAsync().ContinueWithOnMainThread(task =>
{
if(task.IsFaulted)
{
//....
}
QuerySnapshot collectionSnapshot = task.Result;
//....
}
i tried this method that I created but it prompts me an error:
Realms.RealmInvalidObjectException:This object is detached. Was it deleted from the realm?'
public void deleteFromDatabase(List<CashDenomination> denom_list)
{
using (var transaction = Realm.GetInstance(config).BeginWrite())
{
Realm.GetInstance(config).Remove(denom_list[0]);
transaction.Commit();
}
}
what is the proper coding for deleting records from database in realm in C# type of coding?
You are doing it the right way. The error message you are getting indicates that the object was removed already. Are you sure it still exists in the realm?
UPDATE:
I decided to update this answer because my comment on the other answer was a bit hard to read.
Your original code should work fine. However, if you want deleteFromDatabase to accept lists with CashDenomination instances that either have been removed already or perhaps were never added to the realm, you would need to add a check. Furthermore, note that you should hold on to your Realm instance and use it in the transaction you created. In most cases, you want to keep it around even longer, though there is little overhead to obtaining it via GetInstance.
public void deleteFromDatabase(List<CashDenomination> denom_list)
{
if (!denom_list[0].IsValid) // If this object is not in the realm, do nothing.
return;
var realm = Realm.GetInstance(config);
using (var transaction = realm.BeginWrite())
{
realm.Remove(denom_list[0]);
transaction.Commit();
}
}
Now, if you want to use identifiers, you could look it up like you do, but still just use Remove:
public void deleteFromDatabase(int denom_id)
{
var realm = Realm.GetInstance(config);
var denom = realm.All<CashDenomination>().FirstOrDefault(c => c.denom_id == denom_id);
if (denom == null) // If no entry with this id exists, do nothing.
return;
using (var transaction = realm.BeginWrite())
{
realm.Remove(denom);
transaction.Commit();
}
}
Finally, if your CashDenomination has denom_id marked as PrimaryKey, you could look it up like this:
public void deleteFromDatabase(int denom_id)
{
var realm = Realm.GetInstance(config);
var denom = realm.ObjectForPrimaryKey<CashDenomination>(denom_id);
if (denom == null) // If no entry with this id exists, do nothing.
return;
using (var transaction = realm.BeginWrite())
{
realm.Remove(denom);
transaction.Commit();
}
}
public void deleteFromDatabase(Realm realm, long cashDenominatorId)
{
realm.Write(() =>
{
var cashDenominator = realm.All<Person>().Where(c => c.Id == cashDenominatorId);
Realm.RemoveRange<CashDenomination>(((RealmResults<CashDenomination>)cashDenominator));
});
}
Which you would call as
Realm realm = Realm.GetInstance(config);
var denom_list = ...
// ...
deleteFromDatabase(realm, denom_list[0].id);
I already made it having this code :) thanks to #EpicPandaForce 's answer.
public void deleteFromDatabase(int denom_ID, int form_ID)
{
//Realm realm;
//and
//RealmConfiguration config = new RealmConfiguration(dbPath, true);
//was initialized at the top of my class
realm = Realm.GetInstance(config);
realm.Write(() =>
{
var cashflow_denom = realm.All<CashDenomination>().Where(c => c.denom_id == denom_ID);
var cashflow_form = realm.All<CashForm>().Where(c => c.form_id == form_ID);
realm.RemoveRange(((RealmResults<CashDenomination>)cashflow_denom));
realm.RemoveRange(((RealmResults<CashForm>)cashflow_form));
});
}
it is now deleting my data without exception :)
I suspect I have a deadlock issue, but it's an odd one that I can't rationalize. I have an API that needs to verify a few things in order to process the call. As part of the business logic, I might have to make more of those same calls as well. In this case, if a particular piece of data associated with an entity is not found, we attempt to use a backup (if one is configured), which requires checking other entities. Eventually, the code will hang.
Let's just dive into the code (comments highlight the calls in question).
API Controller:
public async Task<HttpResponseMessage> Get(int entityID, string content, bool? useBackUp = true)
{
//Some look-ups here, no issues at all
//This works, but it's this method that has an issue later in the process.
SystemEntity entityObj =
await BusinessLayer.GetSystemEntityAsync(SystemEntityID);
if (entityObj == null)
{
return new HttpResponseMessage
{
StatusCode = System.Net.HttpStatusCode.BadRequest,
Content = new StringContent("Entity is unavailable.")
};
}
string text = BusinessLayer.GetContentTextAsync(entityID
new List<string> {contentName}, useBackUp).Result.FirstOrDefault().Value;
if (text == null)
{
return new HttpResponseMessage {StatusCode = System.Net.HttpStatusCode.NoContent};
}
return new HttpResponseMessage
{
StatusCode = System.Net.HttpStatusCode.OK,
Content = new StringContent(text)
};
}
Business Layer:
public async Task<Dictionary<string, string>> GetContentTextAsync(int systemEntityID, List<string> contentNames, bool useBackUp)
{
Dictionary<string, string> records = new Dictionary<string, string>();
//We iterate for caching purposes
foreach (string name in contentNames)
{
string nameCopy = name;
string record = Cache.GetData(
string.Format("{0}_{1}_{2}", CONTENT, systemEntityID, name), () =>
DataLayer.GetCotnent(systemEntityID, nameCopy));
if (record == null && useBackUp)
{
List<int> entityIDs = new List<int> {systemEntityID};
int currentEntityID = systemEntityID;
//Here's that method again. This call seems to work.
SystemEntity currentEntity = await GetSystemEntityAsync(systemEntityID);
if (currentEntity != null && currentEntity.BackUpID.HasValue)
{
currentEntityID = (int) currentEntity.BackUpID;
}
while (!entityIDs.Contains(currentEntityID))
{
int id = currentEntityID;
record = Cache.GetData(
string.Format("{0}_{1}_{2}", CONTENT, systemEntityID, name), () =>
DataLayer.GetCotnent(id, nameCopy));
if (record != null) break;
entityIDs.Add(currentEntityID);
//This call seems to cause the deadlock
currentEntity = await GetSystemEntityAsync(currentEntityID);
if (currentEntity != null && currentEntity.BackUpID.HasValue)
{
currentEntityID = (int) currentEntity.UseBackupID;
}
}
}
if (record != null)
{
records.Add(name, record);
}
}
return records;
}
public async Task<SystemEntity> GetSystemEntityAsync(int systemEntityID)
{
SystemEntity systemEntity = await DataLayer.GetSystemEntity(
scc => scc.SystemEntityID == systemEntityID);
return systemEntity;
}
Data Layer:
public async Task<SystemEntity> GetSystemEntity(Expression<Func<SystemEntity, bool>> whereExpression)
{
using (EntityContext dbContext = createDbInstance())
{
//This is the last line that the debugger in VS 2013 brings me to. Stepping into this returns to whatever called the API method, waiting endlessly.
return await
dbContext.SystemEntity.Include(sc => sc.OtherEntity).Where(whereExpression).FirstOrDefaultAsync();
}
}
To recap: I call GetSystemEntityAsync three times. The first two times, it completes successfully. The third time, it hangs. If I comment out the first two calls so they don't run at all, the third one still hangs. If I remove the await and use just a normal FirstOrDefault in the return statement of the data layer method, then everything completes just fine.
Note: I have to keep the GetSystemEntityAsync method asynchronous. I cannot alter it to be synchronous.
What are the possible sources of the deadlock I'm encountering? I'm out of ideas on how to solve it.
Which one of these async calls is not like the other?
This one, I suspect:
string text = BusinessLayer.GetContentTextAsync(entityID
new List<string> {contentName}, useBackUp).Result.FirstOrDefault().Value;
Try changing it to this:
string text = (await BusinessLayer.GetContentTextAsync(entityID
new List<string> {contentName}, useBackUp)).FirstOrDefault().Value;
The possible source of the deadlock is described by Stephen Cleary in his "Don't Block on Async Code" blog post.