Programmatically create index - ravendb

How do I create an index programmatically in RavenDB?
I tried to follow this example.
This is my index creator:
public class MyIndex : Raven.Client.Indexes.AbstractIndexCreationTask<MyEntity>
{
public MyIndex()
{
Map = col => col.Select(c => new
{
code = c.Code,
len = c.Code.Length,
sub = c.Code.Substring(0, 1)
});
}
}
And here is the caller:
var store = new Raven.Client.Document.DocumentStore
{
Url = "http://localhost:8080"
};
store.Initialize();
try
{
using (var session = store.OpenSession("MyDB"))
{
Raven.Client.Indexes.IndexCreation.CreateIndexes(
typeof(MyIndex).Assembly, store);
}
}
finally
{
store.Dispose();
}
The index was created but not in MyDB but in system database.
How to create the index in MyDB? Is the way I create index correct?

Try this:
specify the database name in your store object
var store = new Raven.Client.Document.DocumentStore
{
Url = "http://localhost:8080",
DefaultDatabase = "MyDB"
};

As MED pointed out, you can provide a default database when attaching to the document store. When doing so, you no longer pass the database name to the OpenSession method. This is the easiest way, and if you're working with a single database then it is the best answer (and should be given the credit as the answer to this question).
But if you need to work with multiple databases, and thus can't use that technique, then you can use this helper method.
public static void CreateIndexes(Assembly assembly, IDocumentStore store,
string databaseName)
{
var catalog = new AssemblyCatalog(assembly);
var provider = new CompositionContainer(catalog);
var commands = store.DatabaseCommands.ForDatabase(databaseName);
IndexCreation.CreateIndexes(provider, commands, store.Conventions);
}
Call it the same way you would call the other method, but now you can pass the database name as a parameter.

Related

There is no index named: TicketsByPaymentTotal

I have written a code for index creation but when i run the application and try to call it then give a error of 'There is no index named'. My code is as follow :
I have created a class for index creation like :
public class TicketsByPaymentTotal : AbstractIndexCreationTask<Tickets,TicketTotal>
{
public TicketsByPaymentTotal()
{
Map = docs => from doc in docs
select new
{
TicketId = doc.TicketData.ID,
TicketTotalVal = doc.TicketData.PaymentTotal,
TotalVal = doc.TicketData.Total
};
Reduce = results => from result in results
group result by result.TicketId
into g
select new
{
TicketId = g.Key,
TicketTotalVal = g.Sum(x => x.TicketTotalVal),
TotalVal = g.Sum(x => x.TotalVal)
};
}
}
and i am creating index in global.asax file like :
public class MvcApplication : System.Web.HttpApplication
{
public IDocumentSession DocSession;
//DocumentStore store = new DocumentStore{ConnectionStringName="RavenDB2",DefaultDatabase="Dinerware"};
protected void Application_Start()
{
//AreaRegistration.RegisterAllAreas();
DataDocumentStore.Initialize();
DocSession = DataDocumentStore.Instance.OpenSession("Dinerware");
RegisterRoutes(RouteTable.Routes);
//store.Initialize();
HandlerConfig.RegisterHandlers(GlobalConfiguration.Configuration.MessageHandlers);
IndexCreation.CreateIndexes(typeof(TicketsByPaymentTotal).Assembly,DocSession.Advanced.DocumentStore);
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("Default",
"{controller}/{action}/{id}",
new { controller="Home",action="Index",id=""});
}
}
How to solve this issue.
Thanks.
Regards,
sandy
You are creating the index in the system database, even though you are using a named instance called "Dinnerware".
If you want to use a named database, pass it in the DefaultDatabase parameter when you create the document store instance.
Don't pass the name when you are opening the session. That should be reserved for when you have multi-database needs.
You should just pass your document store instance into the CreateIndexes method directly, rather than pulling it out of session.
Don't open a session and assign it to a property. Sessions are meant to be short lived, and must be disposed. Only the document store should be long lived on a single instance. Usually, sessions are created in a using statement. In a web app, a new session should be created for each and every web request.

MS Dynamics CRM. Get users who current record shared with

I have a entity record which is shared with or more users. I would like to unshare this record when Deactivate it. I want to do that in Plugin. But I can't understand how to get all users from sharing list who have access to this record. How to do that?
Here is my code snippet:
protected void ExecutePostPersonSetStateDynamicEntity(LocalPluginContext localContext)
{
if (localContext == null)
{
throw new ArgumentNullException("localContext");
}
var context = localContext.PluginExecutionContext;
var targetEntity = (Entity)context.InputParameters["EntityMoniker"];
var state = (OptionSetValue)context.InputParameters["State"];
var columns = new ColumnSet(new[] { "statecode" });
var retrivedEntity = localContext.OrganizationService.Retrieve(targetEntity.LogicalName, targetEntity.Id, columns);
if (state.Value == 1)
{
RevokeAccessRequest revokeRequest = new RevokeAccessRequest()
{
Target = new EntityReference(personEntity.LogicalName, personEntity.Id),
Revokee = new EntityReference(neededEntity.LogicalName, needed.Id)
};
// Execute the request.
}
}
As you can see, I need an entity "neededEntity", I don't know how to get it from "targetEntity" or "retrievedEntity".
You need to use a RetrieveSharedPrincipalsAndAccessRequest
http://msdn.microsoft.com/en-us/library/microsoft.crm.sdk.messages.retrievesharedprincipalsandaccessrequest.aspx
You can start from the included example, basically inside the foreach you call your RevokeAcessRequest

Delete Indexed In RavenDB not found

I am trying to write a generic delete function for multi tenant ravendb for integration testing the class is -
public class RavenDeleteAll
{
private readonly IDocumentStore _store;
private readonly string _testDataBase;
public RavenDeleteAll(string testDataBase, IDocumentStore store)
{
_testDataBase = testDataBase;
_store = store;
}
public void Clear<T>(string indexName)
{
using (var session = _store.OpenSession(_testDataBase))
{
session.Advanced.DocumentStore.DatabaseCommands.DeleteIndex(indexName);
session.Advanced.DocumentStore.DatabaseCommands.PutIndex(indexName, new IndexDefinitionBuilder<T>
{
Map = documents => documents.Select(entity => new { })
});
var indexDefinition = session.Advanced.DocumentStore.DatabaseCommands.GetIndex(indexName);
session.Advanced.LuceneQuery<T>(indexName)
.WaitForNonStaleResultsAsOfNow()
.Take(0)
.ToList();
session.Advanced.DatabaseCommands.DeleteByIndex(indexName, new IndexQuery());
}
}
}
Note that in the code i try to read back the index after putindex call for sanity check. but when I execute the index it throws an invalidoperationexception stating that /indexes/UTO does not exist?
Also from management console I can clearly see the index -
What am I not doing? Also the index is created under default database and not the actual database name?
It looks like you are creating the index in the Default database not the Tenant Database then asking the Tenant Database for that Index. You need to create the index in the database where you are going to use it. The following is not tested but should work for creating the index in the tenant database.
IDatabaseCommands context = session.Advanced.DocumentStore.DatabaseCommands.ForDatabase(database);
context.PutIndex(indexName, new IndexDefinitionBuilder<T>
{
Map = documents => documents.Select(entity => new { })
});

Generate test data in Raven DB

I am looking for a preferred and maintainable way of test data generation in Raven DB. Currently, our team does have a way to do it through .NET code. Example is provided.
However, i am looking for different options. Please share.
public void Execute()
{
using (var documentStore = new DocumentStore { ConnectionStringName = "RavenDb" })
{
documentStore.Conventions.DefaultQueryingConsistency = ConsistencyOptions.QueryYourWrites;
// Override the default key prefix generation strategy of Pascal case to lower case.
documentStore.Conventions.FindTypeTagName = type => DocumentConvention.DefaultTypeTagName(type).ToLower();
documentStore.Initialize();
InitializeData(documentStore);
}
}
Edit: Raven-overflow is really helpful. Thanks for pointing out to the right place.
Try checking out RavenOverflow. In there, I've got a FakeData project that has fake data (both hardcoded AND randomly generated). This can then be used in either my Tests project or the Main Website :)
Here's some sample code...
if (isDataToBeSeeded)
{
HelperUtilities.CreateSeedData(documentStore);
}
....
public static void CreateSeedData(IDocumentStore documentStore)
{
Condition.Requires(documentStore).IsNotNull();
using (IDocumentSession documentSession = documentStore.OpenSession())
{
// First, check to make sure we don't have any data.
var user = documentSession.Load<User>(1);
if (user != null)
{
// ooOooo! we have a user, so it's assumed we actually have some seeded data.
return;
}
// We have no users, so it's assumed we therefore have no data at all.
// So let's fake some up :)
// Users.
ICollection<User> users = FakeUsers.CreateFakeUsers(50);
StoreFakeEntities(users, documentSession);
// Questions.
ICollection<Question> questions = FakeQuestions.CreateFakeQuestions(users.Select(x => x.Id).ToList());
StoreFakeEntities(questions, documentSession);
documentSession.SaveChanges();
// Make sure all our indexes are not stale.
documentStore.WaitForStaleIndexesToComplete();
}
}
....
public static ICollection<Question> CreateFakeQuestions(IList<string> userIds, int numberOfFakeQuestions)
{
.... you get the idea .....
}

RavenDB adds integer to ID when ends with a slash

I use RavenDB 1.0.0.426
I just experienced a weird scenario when importing data from an external source into RavenDB:
I chose to use the same unique ID as the external source uses, prefixed with a certain string. But. When I store a document with an ID that ends with a '/', raven automatically adds a number to the end of the ID, causing the document to NOT overwrite existing document stored with the same id.
I have recreated a simple scenario to cause the error:
The type I save:
public class Foo
{
public string Id { get; set; }
public Foo(string id)
{
Id = id;
}
}
Method saving a doc with the same id 10 times and afterwards checks the document count:
public void RunTest(string id)
{
for (int i = 0; i < 10; i++)
{
using (var doc = new DocumentStore() { Url = "http://pc-009:8080/" })
{
doc.Initialize();
using (var session = doc.OpenSession())
{
session.Store(new Foo(id));
session.SaveChanges();
}
}
}
// Wait for the data to be persisted
Thread.Sleep(2000);
using (var doc = new DocumentStore() { Url = "http://pc-009:8080/" })
{
doc.Initialize();
using (var session = doc.OpenSession())
{
var foos = session.Query<Foo>();
int fooCount = foos.Count();
// ASSERT HERE THAT fooCount is 1
}
}
}
Running the method with "id1" successfully overwrites existing documents:
RunTest("id1"); // Works fine
Running method with "id1/" ends up creating 10 documents in the database:
RunTest("id1/"); // Results in multiple documents to be created
I know that if you do not define your own ID, raven will autogenerate doc-ids on the fly, but is the behavior I describe above by design?
Thankyou in advance
Stephan,
This is expected, when your key ends with /, it asks ravendb to use identity generation strategy.
See the docs here:
http://ravendb.net/documentation/docs-api-key-generation
If you want a key that ends with /, you can url encode the keys