I'm using RavenDB Embedded. Build 888.
Have photos collection:
public class Photo
{
private Dictionary<string, VoteDictionaryValue> _votes = new Dictionary<string, VoteDictionaryValue>();
public Photo()
{
Created = DateTime.Now;
}
public string Id { get; set; }
public string Title { get; set; }
public string UserId { get; set; }
public string Image { get; set; }
public DateTime Created { get; private set; }
public Dictionary<string, VoteDictionaryValue> Votes
{
get { return _votes; }
protected set { _votes = value; }
}
}
Have index:
public class PhotosSortByCreated : AbstractIndexCreationTask<Photo>
{
public PhotosSortByCreated()
{
Map = photos => from photo in photos
select new {photo.Created};
Store(x => x.Created, FieldStorage.No);
Sort(x => x.Created, SortOptions.String);
}
}
and query:
RavenQueryStatistics stat;
var query = from photo in RavenSession.Query<Photo>()
orderby photo.Created descending
select photo;
var result = query.Statistics(out stat).Skip(page*pageSize).Take(pageSize).Customize(x => x.WaitForNonStaleResults(TimeSpan.FromSeconds(3))));
Add 10 photos, one by one.
by this query I get only first 5-6.
all new added photos will not returned.
after pool restart I can add 5-6 new photos, before ravenDB stops index them.
all added photos saved in DB, but they are not indexed.
why?
Thanks in advance.
Add:
RavenSession.Query<Photo>().Customize(x=>x.WaitForNonStaleResultsAsOfNow())
What happens?
Related
I'm not sure why while trying to create an entity which is 1:many
EF tries to add new entry in Asp Net Users instead of update 1:many
I have one user which has many items
SqlException: Violation of PRIMARY KEY constraint 'PK_AspNetUsers'. Cannot insert duplicate key in object 'dbo.AspNetUsers'. The duplicate key value is (cdbb1f2f-ddcf-40c0-97ec-f50f8049d87a).
public class Context : IdentityDbContext
{
public Context(DbContextOptions options) : base(options)
{
}
public DbSet<User> Users { get; set; }
public DbSet<Item> Items { get; set; }
public DbSet<File> Files { get; set; }
}
public class User : IdentityUser
{
public List<Item> Items { get; set; } = new List<Item>();
}
public class Item
{
private Item()
{
}
public Item(string title, User owner, File file)
{
Title = title;
Owner = owner;
File = file;
}
public int Id { get; private set; }
public string Title { get; set; }
public User Owner { get; set; }
public File File { get; set; }
public DateTime CreationDate { get; } = DateTime.Now;
}
And here's where's the problem:
var fileResult = await _file.SaveFile(input.File);
var item = new Item(input.Title, user, fileResult.File);
user.Items.Add(item);
await _context.Items.AddAsync(item);
await _context.SaveChangesAsync();
User is loaded with:
public User GetUser()
{
return _context.Users.FirstOrDefault(x => x.UserName == _http.HttpContext.User.Identity.Name);
}
I tried that:
When I change
public Item(string title, User owner, File file)
{
Title = title;
Owner = owner;
File = file;
}
to just:
public Item(string title, File file)
{
Title = title;
File = file;
}
and let it be handled by:
user.Items.Add(item);
then OwnerId in DB is null
Using:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>()
.HasMany(x => x.Items)
.WithOne(x => x.Owner);
modelBuilder.Entity<Item>().HasOne(x => x.Owner);
}
is not helping either
The problem was casued by ServiceLifetime of DbContext
Because User was loaded in Controller and then thrawn into Service that was responsible for business logic
I changed
(options => options.UseSqlServer(Configuration["Database:ConnectionString"]), ServiceLifetime.Transient);
to
(options => options.UseSqlServer(Configuration["Database:ConnectionString"]), ServiceLifetime.Scoped);
and it works fine.
I followed this link enter link description here to create many to many relationship. But, I do not know how to create and update Tag value to Post Object.
Any help would be appreciated.
Update, related code
class MyContext : DbContext
{
public DbSet<Post> Posts { get; set; }
public DbSet<Tag> Tags { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<PostTag>()
.HasKey(t => new { t.PostId, t.TagId });
modelBuilder.Entity<PostTag>()
.HasOne(pt => pt.Post)
.WithMany(p => p.PostTags)
.HasForeignKey(pt => pt.PostId);
modelBuilder.Entity<PostTag>()
.HasOne(pt => pt.Tag)
.WithMany(t => t.PostTags)
.HasForeignKey(pt => pt.TagId);
}
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class Tag
{
public string TagId { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class PostTag
{
public int PostId { get; set; }
public Post Post { get; set; }
public string TagId { get; set; }
public Tag Tag { get; set; }
}
Update2: Code for Update record
With below code, it will create records in both three tables.
var p = new Post { Content = "C1" };
var t = new Tag { TagId = "T1" };
var pt = new PostTag { Post = p, Tag = t };
_context.PostTag.Add(pt);
_context.SaveChanges();
But, with below code, it will insert new records in middle table PostTag instead of update the previous records.
var t1 = new Tag { TagId = "T3" };
var t2 = new Tag { TagId = "T4" };
var p =_context.Posts.Find(1);
p.PostTags = new List<PostTag>() {
new PostTag{ Post=p, Tag=t1},
new PostTag{ Post=p, Tag=t2}
};
_context.Posts.Update(p);
_context.SaveChanges();
Let's create some sample data
var p = new Post { ... };
var t = new Tag { ... };
var pt = new PostTag { Post = p, Tag = t };
This is still in-memory so we have to add it to the context, starting with:
db.Posts.Add(p);
db.Tags.Add(t);
Note that at this stage neither p nor t has any knowledge of pt. There are two ways to insert the third entity into your database.
1) The easiest way is to add the DbSet<PostTag> property and then the line
db.PostTags.Add(pt);
2) Without that extra DbSet you will need to ensure the linking from the other 2 sides. You also need to set up the List properties:
p.PostTags = new List<PostTag> { pt };
t.PostTags = new List<PostTag> { pt };
EF will now fill out any missing link fields.
Query Code:
var query = session.IndexQuery<App_OrgSearch.IndexResult, App_OrgSearch>();
var organizationUnitResults = query.Statistics(out stats)
.Skip(0)
.Take(5)
.AsProjection<Org>().ToList();
public static IRavenQueryable<TResult> IndexQuery<TResult, TIndex>(this IDocumentSession session)
where TIndex : AbstractIndexCreationTask, new()
{
return session.Query<TResult, TIndex>();
}
App_OrgSearch is the index I defined as below:
public class App_OrgSearch : AbstractIndexCreationTask<Org, App_OrgSearch.IndexResult>
{
public class IndexResult
{
public string Id { get; set; }
public string BusinessName { get; set; }
public string ShortName { get; set; }
public IList<string> Names { get; set; }
public List<string> PhoneNumbers { get; set; }
public List<OrganizationUnitPhone> OrganizationUnitPhones { get; set; }
}
public App_OrganizationUnitSearch()
{
Map = docs => from doc in docs
select new
{
Id = doc.Id,
Names = new List<string>
{
doc.BusinessName,
doc.ShortName,
},
BusinessName = doc.BusinessName,
ShortName = doc.ShortName,
PhoneNumbers = doc.OrganizationUnitPhones.Where(x => x != null && x.Phone != null).Select(x => x.Phone.Number),
};
Indexes.Add(x => x.Names, FieldIndexing.Analyzed);
}
}
I have 27 records in database. I want to take 5, but after query, all 27 records are returned. Why does Take function not work?
Your sample code seems wrong.
var query = session.IndexQuery<App_OrgSearch.IndexResult, App_OrgSearch>();
var organizationUnitResults = organizationUnitsQuery.Statistics(out stats)
What is organizationUnitsQuery ? You have the query as query, but there is no IndexQuery method on the session
I'm new to RavenDB and I have a question about joining two documents with Raven 2.0
I found this page http://daniellang.net/joining-documents-in-ravendb-2-0/ that helped me in finding a solution to join two documents.
Please see my code first (it compiles)
internal class Program
{
private static void Main(string[] args)
{
using (var store = new EmbeddableDocumentStore {DataDirectory = #"C:\temp\ravendata"}.Initialize())
{
using (var session = store.OpenSession())
{
var products = session.Query<Product, UserProducts>()
.AsProjection<UserProductProjection>()
.ToList();
}
}
}
}
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
public string UserId { get; set; }
}
public class User
{
public string Id { get; set; }
public string Name { get; set; }
}
public class UserProductProjection
{
public string Id { get; set; }
public string UserName { get; set; }
public string ProductName { get; set; }
public string ProductId { get; set; }
}
internal class UserProducts : AbstractIndexCreationTask<Product, UserProductProjection>
{
public UserProducts()
{
Map = products => from product in products
select new
{
UserName = LoadDocument<User>(product.UserId).Name,
ProductName = product.Name,
ProductId = product.Id
};
Index(projection => projection.ProductId, FieldIndexing.Analyzed);
Index(projection => projection.ProductName, FieldIndexing.Analyzed);
Store(projection => projection.UserName, FieldStorage.Yes);
}
}
Unfortunately it doesn't work :(
Raven.Database.Exceptions.IndexDoesNotExistsException was unhandled
HResult=-2146233088
Message=Could not find index named: UserProducts
Source=Raven.Database
StackTrace:
at Raven.Database.DocumentDatabase.<>c__DisplayClass9a.<Query>b__90(IStorageActionsAccessor actions) in c:\Builds\RavenDB-Stable\Raven.Database\DocumentDatabase.cs:line 1100
....
I really have NO clue at all!! Google doesn't help me on this subject as well, because it is still pretty new as I found out.
If someone has a hint or a solution I would be very grateful.
While you have defined the index you haven't created it in ravendb.
See Defining a static index but basically you need....
IndexCreation.CreateIndexes(typeof(UserProducts).Assembly, documentStore);
I have an index that works great when I query it using the .Net client API with a server based RavenDb.
However, if I change the RavenDb to an embedded type then I cannot query the index directly unless I first query the document that the index uses.
For instance if I have the following document objects which reside as separate collections in the RavenDb:
private class TestParentDocument
{
public string Id { get { return GetType().Name + "/" + AggregateRootId; } }
public Guid AggregateRootId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
private class TestChildProductFlagDocument
{
public string TestParentDocumentId { get; set; }
public short ProductFlagTypeId { get; set; }
}
Then I have the following object which represents the output document that the index maps to:
private class TestJoinIndexOutput
{
public string TestParentDocumentId { get; set; }
public string Name { get; set; }
public short ProductFlagTypeId { get; set; }
}
Here is the index definition:
private class TestJoinIndex : AbstractIndexCreationTask<TestChildProductFlagDocument, TestJoinIndexOutput>
{
public TestJoinIndex()
{
Map = docs => from doc in docs
select new
{
TestParentDocumentId = doc.TestParentDocumentId,
ProductFlagTypeId = doc.ProductFlagTypeId
};
TransformResults = (database, results) =>
from result in results
let parentDoc = database.Load<TestParentDocument>(result.TestParentDocumentId)
select new
{
TestParentDocumentId = result.TestParentDocumentId,
ProductFlagTypeId = result.ProductFlagTypeId,
Name = parentDoc.Name
};
}
My code to call the index looks like so:
var theJoinIndexes = ravenSession.Query<TestJoinIndexOutput, TestJoinIndex>().ToList();
This returns almost immediately and fails unless I do the following:
var theParentDocuments = ravenSession.Query<TestParentDocument>().ToList();
var theJoinIndexes = ravenSession.Query<TestJoinIndexOutput, TestJoinIndex>().ToList();
My Ravendb embedded definition looks like so:
docStore = new EmbeddableDocumentStore
{
UseEmbeddedHttpServer = false,
RunInMemory = true
};
docStore.Configuration.Port = 7777;
docStore.Initialize();
IndexCreation.CreateIndexes(typeof(TestJoinIndex).Assembly, docstore);
You aren't waiting for indexing to complete, call WaitForNonStaleResultsAsOfNow