I need to make a query against a document collection that matches several properties.
(Cross post from the mailing list: https://groups.google.com/forum/?fromgroups=#!topic/ravendb/r5f1zr2jd_o)
Here is the document:
public class SessionToken
{
[JsonProperty("jti")]
public string Id { get; set; }
[JsonProperty("aud")]
public Uri Audience { get; set; }
[JsonProperty("sub")]
public string Subject { get; set; }
[JsonProperty("claims")]
public Dictionary<string, string> Claims { get; set; }
}
And here is the test:
[TestFixture]
public class RavenDbTests
{
private IDocumentStore documentStore;
[SetUp]
public void SetUp()
{
this.documentStore = new EmbeddableDocumentStore() { RunInMemory = true };
this.documentStore.Initialize();
}
[Test]
public async void FirstOrDefault_WhenSessionTokenExists_ShouldReturnSessionToken()
{
var c = new SessionToken()
{
Audience = new Uri("http://localhost"),
Subject = "NUnit",
Claims = new Dictionary<string, string>()
{
{ ClaimTypes.System, "NUnit" }
}
};
using (var session = this.documentStore.OpenAsyncSession())
{
await session.StoreAsync(c);
await session.SaveChangesAsync();
// Check if the token exists in the database without using Where clause
var allTokens = await session.Query<SessionToken>().ToListAsync();
Assert.That(allTokens.Any(x => x.Subject == "NUnit" && x.Audience == new Uri("http://localhost")));
// Try getting token back with Where clause
var token = await session.Query<SessionToken>().Customize(x => x.WaitForNonStaleResults()).Where(x => x.Subject == "NUnit" && x.Audience == new Uri("http://localhost")).ToListAsync();
Assert.IsNotNullOrEmpty(token.First().Id);
}
}
}
The last Assert is the one that is failing.
I must admit Im not sure whether this is a bug or a failure on my part.
As far as I understand, this is supposed to work.
PS. I´ve tried with a standalone document store as well as embedded without running in memory, but with same result.
You are getting stale results. In a unit test, you need to allow time for indexing to occur.
Add .Customize(x=> x.WaitForNonStaleResults()) to your queries and the test should pass.
Also, I think you left the Id property off your question when you cut/paste because it doesn't compile as-is.
UPDATE
Per discussion in comments, the issue was that you were applying the [JsonProperty] attribute to the Id property. Since the Id property represents the document key, and is not serialized as part of the JSON document, you can't apply the [JsonProperty] attribute to it.
Related
Since the two following controller's actions are possible, I am wondering if there is any difference in terms of performance (or best practices) between them.
[HttpGet("example1")]
public ActionResult<User> GetExample1()
{
var user = new User { UserName = "Example 1 user" };
var model = new Model<User>(user);
return Ok(model);
}
[HttpGet("example2")]
public ActionResult<Model<User>> GetExample2()
{
var user = new User { UserName = "Example 2 user" };
var model = new Model<User>(user);
return Ok(model);
}
Please notice that the only difference between the two is the returned type of the generic parameter of ActionResult (User vs Model<User>). Is there any important internal differences when the ActionResult object is formatting out the result?.
User and Model code for this example:
public class User
{
public string UserName { get; set; }
}
public class Model<T>
{
public T Data { get; set; }
public Model(T data)
{
Data = data;
}
}
I have simple model:
public class Post
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { set; get; }
//non-important properties stripped, to focus on problem
public virtual Resource Resource { set; get; }
public virtual ICollection<Tag> Tags { set; get; }
}
public class Resource
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { set; get; }
[Url]
public string Url { set; get; }
}
and DbContext (I use ASP.NET identity in this project, if this is relevant):
public class DbContext : IdentityDbContext<User>
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
var postEntity = modelBuilder.Entity<Post>();
postEntity.Reference(p => p.Resource).InverseCollection(); //no navigation property on Resource side
postEntity.Collection(p => p.Tags).InverseReference(tag => tag.Post);
postEntity.ToTable("Posts");
var resourceEntity = modelBuilder.Entity<Resource>();
resourceEntity.ToTable("Resources");
var tagEntity = modelBuilder.Entity<Tag>();
tagEntity.Reference(t => t.Post).InverseCollection(p => p.Tags).Required(false);
tagEntity.ToTable("Tags");
}
}
After migration (SQL Server), database tables looks like expected - Post table has Foreign Key to ResourceId.
Creating Post's works fine, when I attach post.Resource (already created Resource).
My problem occurs when I want to replace post.Resource.
By replace, I mean selecting one of already existing Resources and assigning it to post.
var resource2 = Database.Resources.First(r=>r.Url == "xyz");
I have tried:
post.Resource = resource2; Database.Entry(post).State = EntityState.Modified;
Database.Entry(post).Property(p => p.Resource).CurrentValue = resource2;
post.Resource = null;
With different combinations of them also, but none of them works. After calling await SaveChangesAsync(); and looking up in database - there are no changes. How to perform the replace (update of foreign key) properly?
//Update 14.09.2015
Issue was caused by additional select, performed to update One-To-Many relationship. Full code:
var Database new DbContext();
var resource2 = Database.Resources.First(r=>r.Url == "xyz");
var oldAssignedTags = Database.Posts.Include(p=>p.Tags).FirstOrDefault(p => p.Id == post.Id).Tags;
var tags = newTags as List<Tag> ?? newTags.ToList();
//TagComparer is irrelevant here
var toRemove = oldAssignedTags.Except(tags, TagComparer);
var toAdd = tags.Except(oldAssignedTags, TagComparer);
foreach (var tag in toRemove)
{
Database.Entry(tag).State = EntityState.Deleted; //Database.Tags.Remove(tag);
}
foreach (var tag in toAdd)
{
tag.Post = post;
post.Tags.Add(tag);
}
post.Resource = resource2;
await Database.SaveChangesAsync();
I thought this may have something to do with Eager Loading, however I can't reproduce your issue with or without AspNet.Identity. Running the below code results in the Resource always being updated. Using EntityFramework 7.0.0-beta7.
Code
static void Main(string[] args)
{
Init();
WithEagerLoading();
CleanUp();
Init();
WithoutEagerLoading();
CleanUp();
}
private static void WithoutEagerLoading()
{
var db = new MyContext();
var post = db.Posts.First(); // no eager loading of child
post.Resource = db.Resources.First(p => p.Url == "http://trend.atqu.in");
db.SaveChanges();
Console.WriteLine($"2nd Resource.Id: {new MyContext().Posts.Include(p => p.Resource).First().Resource.Id}");
}
private static void WithEagerLoading()
{
var db = new MyContext();
var post = db.Posts
.Include(p => p.Resource) // eager loading
.First();
post.Resource = db.Resources.First(p => p.Url == "http://trend.atqu.in");
db.SaveChanges();
Console.WriteLine($"2nd Resource.Id: {new MyContext().Posts.Include(p => p.Resource).First().Resource.Id}");
}
private static void CleanUp()
{
var db = new MyContext();
db.Posts.RemoveRange(db.Posts);
db.Resources.RemoveRange(db.Resources);
db.SaveChanges();
}
private static void Init()
{
var db = new MyContext();
var resource = new Resource { Url = "http://atqu.in" };
var resource2 = new Resource { Url = "http://trend.atqu.in" };
var post = new Post { Resource = resource };
db.Add(post);
db.Add(resource);
db.Add(resource2);
db.SaveChanges();
db = new MyContext();
post = db.Posts.Include(p => p.Resource).First();
resource = db.Resources.First(p => p.Url == "http://trend.atqu.in");
Console.WriteLine($"1st Resource.Id: {post.Resource.Id}");
}
Result
1st Resource.Id: 0f4d222b-4184-4a4e-01d1-08d2bc9cea9b
2nd Resource.Id: 00ccae9c-f0da-43e6-01d2-08d2bc9cea9b
1st Resource.Id: 749f08f0-2426-4043-01d3-08d2bc9cea9b
2nd Resource.Id: 2e83b512-e8bd-4583-01d4-08d2bc9cea9b
Edit 16/9
The problem in the edited question's code is because you are instantiating Database after you have retrieved post. post is not attached to that instance of Database, so when you attach the Resource to it and call SaveChangesAsync it does nothing, because post at that time has noting to do with the Database you are saving against. That is why your workaround of selecting post post again (after the instantiation) causes it to be fixed - because then the instance of post is attached. If you don't want to select post again, you should use the same DbContext instance to do the work above that you used to originally retrieve post.
We have a Web app (ASP.NET/C#) with SQL Server backend. We use ServiceStack OrmLite as our POCO Micro ORM. We would now like to extend a part of our app to cache frequently-read data (mainly a collection of POCO objects as values, with numeric keys). But I'm not sure how to go about integrating a simple caching solution (in-memory or Redis based) that works seamlessly with OrmLite and MSSQL as the Master database.
I've read about the ServiceStack Redis Client, MemoryCacheClient and Multi nested database connections (OrmLiteConnectionFactory), but I couldn't find any examples, tutorial or code samples to learn more about implementing caching that works with OrmLite.
Any suggestions or links will be helpful and much appreciated.
I use this extension to help simplify the integration between the db and the cache.
public static class ICacheClientExtensions
{
public static T ToResultUsingCache<T>(this ICacheClient cache, string cacheKey, Func<T> fn, int hours = 1) where T : class
{
var cacheResult = cache.Get<T>(cacheKey);
if (cacheResult != null)
{
return cacheResult;
}
var result = fn();
if (result == null) return null;
cache.Set(cacheKey, result, TimeSpan.FromHours(hours));
return result;
}
}
public class MyService : Service
{
public Data Get(GetData request)
{
var key = UrnId.Create<Data>(request.Id);
Func<Data> fn = () => Db.GetData(request.Id);
return Cache.ToResultUsingCache(key, fn);
}
[Route("/data/{id}")]
public class GetData: IReturn<Data>
{
public int Id{ get; set; }
}
}
You'd need to implement the caching logic yourself, but it's not much work - here's a pseudocode example:
public class QueryObject
{
public DateTime? StartDate { get; set; }
public string SomeString { get; set; }
}
public class Foo
{
public DateTime DateTime { get; set; }
public string Name { get; set; }
}
public class FooResponse
{
public List<Dto> Data { get; set; }
}
public FooResponse GetFooData(QueryObject queryObject)
{
using (var dbConn = connectionFactory.OpenDbConnection())
using (var cache = redisClientsManager.GetCacheClient())
{
var cacheKey = string.Format("fooQuery:{0}", queryObject.GetHashCode()); //insert your own logic for generating a cache key here
var response = cache.Get<Response>(cacheKey);
//return cached result
if (response != null) return response;
//not cached - hit the DB and cache the result
response = new FooResponse()
{
Data =
dbConn.Select<Foo>(
x => x.DateTime > queryObject.StartDate.Value && x.Name.StartsWith(queryObject.SomeString)).ToList()
};
cache.Add(cacheKey, response, DateTime.Now.AddMinutes(15)); //the next time we get the same query in the next 15 mins will return cached result
return response;
}
}
Have you checked Service stack caching wiki. It gives detailed info about caching. Now in your case from the details you are providing I can say that you can go for any kind of caching. As of now it will not make any difference.
PS: A piece of advice caching should be done when there is no option or the only thing pending in application. Because it comes with it's own problem is invalidating caching, managing and all that. So, if you application is not too big, just leave it for now.
I have the same issue as this question on MSDN, but I don't understand the solution because it is still not clear to me if Roman Kiss's solution will correctly replace an endpoint address while a single workflow instance being executed concurrently.
When internal Send activity is scheduled for execution by one thread with certain enpoint address, wouldn't this address be overridden by another thread that schedules same activity with different endpoint address? Correct me if I am mistaken, but I assume it would, because Send.Endpoint is a regular property as oppose to being InArgument<Endpoint> bound to whatever current workflow execution context is.
Can someone shed more light onto this?
UPDATE
I tested the solution provided by Roman Kiss, and it turns out that it is not working as expected in my scenario. I modified Execute method as follows:
protected override void Execute(NativeActivityContext context)
{
Thread.Sleep(Address.Get(context).EndsWith("1") ? 1000 : 0);
Body.Endpoint.Binding = GetBinding(Binding.Get(context));
Body.Endpoint.AddressUri = new Uri(Address.Get(context));
Thread.Sleep(Address.Get(context).EndsWith("1") ? 0 : 3000);
var address = Address.Get(context) + " => " + Body.Endpoint.AddressUri;
Console.WriteLine(address);
Thread.Sleep(10000);
context.ScheduleActivity(Body);
}
Ran this test:
static void Main(string[] args)
{
// Workflow1 is just a SendScope wrapped around by a Sequence with single Address input argument exposed
var workflow = new Workflow1();
Task.WaitAll(
Task.Run(() => WorkflowInvoker.Invoke(workflow, new Dictionary<string, object> { { "Address", #"http://localhost/1" } })),
Task.Run(() => WorkflowInvoker.Invoke(workflow, new Dictionary<string, object> { { "Address", #"http://localhost/2" } })));
Console.ReadLine();
}
The result I am getting is:
http://localhost/1 => http://localhost/1
http://localhost/2 => http://localhost/1
The question remains open: how do I assign endpoint address of my Send activity dynamically at runtime?
This will work as shown because a new Send activity is created by the factory and so when using the CacheMetadata method to setup that Send activity it is setting the binding properly on that instance of the activity.
Including Content Incase Link Dies
[ContentProperty("Body")]
public class SendScope : NativeActivity
{
[DefaultValue((string)null)]
[RequiredArgument]
public InArgument<string> Binding { get; set; }
[DefaultValue((string)null)]
[RequiredArgument]
public InArgument<string> Address { get; set; }
[Browsable(false)]
public Send Body { get; set; }
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
if (this.Body == null || this.Body.EndpointAddress != null)
{
metadata.AddValidationError("Error ...");
return;
}
this.Body.Endpoint = new Endpoint()
{
AddressUri = new Uri("http://localhost/"),
Binding = new BasicHttpBinding(),
ServiceContractName = this.Body.ServiceContractName
};
metadata.AddChild(this.Body);
base.CacheMetadata(metadata);
}
protected override void Execute(NativeActivityContext context)
{
this.Body.Endpoint.Binding = GetBinding(this.Binding.Get(context));
this.Body.Endpoint.AddressUri = new Uri(this.Address.Get(context));
context.ScheduleActivity(Body);
}
private System.ServiceModel.Channels.Binding GetBinding(string binding)
{
if (binding == "basicHttpBinding")
return new BasicHttpBinding();
//else ... others bindings
return null;
}
}
public class SendScopeFactory : IActivityTemplateFactory
{
public Activity Create(DependencyObject target)
{
return new SendScope()
{
DisplayName = "SendScope",
Body = new Send()
{
Action = "*",
OperationName = "ProcessMessage",
ServiceContractName = "IGenericContract",
}
};
}
}
Create a custom native activity for setting Send.Endpoint property during the runtime based on your properties such as Binding, Address, Security, etc.
Create designer for this SendScope activity something simular like CorrelationScope
Create SendScopeFactory - see the above code snippet.
I want to create a composite Windows Workflow Activity (under .NET 4) that contains a predefined ReceiveAndSendReply Activity. Some of the properties are predefined, but others (particularly ServiceContractName) need to be set in the designer.
I could implement this as an Activity Template (the same way ReceiveAndSendReply is implemented), but would rather not. If I later change the template, I'd have to update all previously created workflows manually. A template would also permit other developers to change properties that should be fixed.
Is there a way to do this from a Xaml Activity? I have not found a way to assign an Argument value to a property of an embedded Activity. If not, what technique would you suggest?
I haven't done this using a composite XAML activity and am getting some errors when I try but doing so through a NativeActivity is no problem. See the example code below.
public class MyReceiveAndSendReply : NativeActivity
{
private Receive _receive;
private SendReply _sendReply;
public string ServiceContractName { get; set; }
public string OperationName { get; set; }
protected override bool CanInduceIdle
{
get { return true; }
}
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
_receive = _receive ?? new Receive();
_sendReply = _sendReply ?? new SendReply();
_receive.CanCreateInstance = true;
metadata.AddImplementationChild(_receive);
metadata.AddImplementationChild(_sendReply);
_receive.ServiceContractName = ServiceContractName;
_receive.OperationName = OperationName;
var args = new ReceiveParametersContent();
args.Parameters["firstName"] = new OutArgument<string>();
_receive.Content = args;
_sendReply.Request = _receive;
var results = new SendParametersContent();
results.Parameters["greeting"] = new InArgument<string>("Hello there");
_sendReply.Content = results;
base.CacheMetadata(metadata);
}
protected override void Execute(NativeActivityContext context)
{
context.ScheduleActivity(_receive, ReceiveCompleted);
}
private void ReceiveCompleted(NativeActivityContext context, ActivityInstance completedInstance)
{
context.ScheduleActivity(_sendReply);
}
}