I've got a spatial index and search working in a prototype and now I'm trying to integrate it into our proper solution that has a slightly different data model and it's not coming back with any search results.
These are my classes
public class SpatialDataModel
{
public int Id { get; set; }
public string Title { get; set; }
public SpatialDataShapeModel SpatialDataShape { get; set; }
}
public class SpatialDataShapeModel
{
public int Id { get; set; }
public DbGeography Shape { get; set; }
}
I've defined the index a couple of ways:
public class SpatialDatasIndex: AbstractIndexCreationTask<SpatialDataModel>
{
public SpatialDatasIndex()
{
Map = points => from p in points
select new
{
Id = p.Id,
__ = SpatialGenerate("Coords", p.SpatialDataShape.Shape.Latitude, p.SpatialDataShape.Shape.Longitude)
};
}
}
and
public class SpatialDatasIndex: AbstractIndexCreationTask<SpatialDataModel>
{
public SpatialDatasIndex()
{
Map = points => from p in points
select new
{
Id = p.Id,
__ = SpatialGenerate("Coords", p.SpatialDataShape.Shape.AsText())
};
Spatial(x=>x.SpatialDataShape.Shape, o=>o.Geography.Default());
}
}
Here i'm using the type DbGeography and and trying to get out the WKT
and I'm trying to query like this:
using (var session = _documentStore.OpenSession())
{
data = session.Query<SpatialDataModel, SpatialDatasIndex>()
.Customize(x => x.WithinRadiusOf(
fieldName: "Coords",
radius: 1,
latitude: query.Lat,
longitude: query.Lng))
.Take(query.PageSize)
.ToList();
}
Any help getting this working would be great, I can't find much documentation and the bits on the Raven site I've read many times.
UPDATE
JSON
{
"Title": "Test 1",
"SpatialDataShape": {
"Id": 1,
"Shape": {
"Geography": {
"CoordinateSystemId": 4326,
"WellKnownText": "POINT (-0.1217937469482422 51.51461834694225)"
}
}
}
}
Related
There are a lot of examples how to use Fluent API in the internet, but mostly shows how configure one relationship between two models. In my case I need 3 relationships between 2 models. How to configure relationships between models below with Fluent API?
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
public int FinanceEstimateId { get; set; }
public Estimate FinanceEstimate { get; set; }
public int EnvironmentEstimateId { get; set; }
public Estimate EnvironmentEstimate { get; set; }
public int SelfEstimateId { get; set; }
public Estimate SelfEstimate { get; set; }
}
public class Estimate
{
public int Id { get; set; }
public string Name { get; set; } // like: bad, good, excellent
public float Value { get; set; } // like: 1,2,3
}
Maybe this points you in the right direction.
I would go for 2 configurations like:
public class CompanyConfiguration : IEntityTypeConfiguration<Company>
{
public void Configure(EntityTypeBuilder<Company> builder)
{
builder.ToTable("Companies");
builder
.HasOne(x => x.EnvironmentEstimate)
.WithMany()
.HasForeignKey(x => x.EnvironmentEstimateId)
.OnDelete(DeleteBehavior.NoAction);
builder
.HasOne(x => x.FinanceEstimate)
.WithMany()
.HasForeignKey(x => x.FinanceEstimateId)
.OnDelete(DeleteBehavior.NoAction);
builder
.HasOne(x => x.SelfEstimate)
.WithMany()
.HasForeignKey(x => x.SelfEstimateId)
.OnDelete(DeleteBehavior.NoAction);
}
}
public class EstimateConfiguration : IEntityTypeConfiguration<Estimate>
{
public void Configure(EntityTypeBuilder<Estimate> builder)
{
builder.ToTable("Estimates");
}
}
You need a DbContext:
public class MyDbContext : DbContext
{
public DbSet<Company> Companies { get; set; } = null!;
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(#"CONNECTIONSTRING");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// applies the configuration (those IEntityTypeConfiguration<T> things)
modelBuilder.ApplyConfigurationsFromAssembly(typeof(MyDbContext).Assembly);
}
}
I created a console application that demonstrates the usage
using var ctx = new MyDbContext();
await ctx.Database.EnsureDeletedAsync();
await ctx.Database.EnsureCreatedAsync();
var company1 = new Company
{
Name = "Name1",
EnvironmentEstimate = new Estimate { Name = "EnvironmentEstimate1", Value = 1 },
FinanceEstimate = new Estimate { Name = "FinanceEstimate1", Value = 2 },
SelfEstimate = new Estimate { Name = "SelfEstimate1", Value = 3 }
};
var company2 = new Company
{
Name = "Name2",
EnvironmentEstimate = new Estimate { Name = "EnvironmentEstimate2", Value = 4 },
FinanceEstimate = new Estimate { Name = "FinanceEstimate2", Value = 5 },
SelfEstimate = new Estimate { Name = "SelfEstimate2", Value = 6 }
};
await ctx.Companies.AddAsync(company1);
await ctx.Companies.AddAsync(company2);
await ctx.SaveChangesAsync();
var result = await ctx.Companies.ToListAsync();
Console.WriteLine("Done");
Am using .net core +angular 5, and trying to return a list, but one field is null in JSON response. Am using Postman to trigger debugging and saw in VS that the field has a value coming from the DB.
Don't know why it doesn't in the JSON response.
[HttpGet("[action]")]
public IEnumerable<HikingTrail> HikingTrails()
{
var dbOptions = new DbContextOptionsBuilder<HikingTrailContext>();
dbOptions.UseSqlServer("Server = (localdb)\\mssqllocaldb; Database = HikingApp");
var dbContext = new DAO.HikingTrailContext(dbOptions.Options);
return dbContext.HikingTrails.ToList();
}
This returns:
I'm interested in the "mountainRange" field not being null. In debug window it has the right value.
{
"url": null,
"hikingTrailId": 159,
"mountainRange": null,
"name": "My custom name",
"startPoint": null,
"endPoint": null,
"trailCheckpoints": null,
"type": 2,
"dificulty": null,
"duration": "2 1/2 - 3 h",
"minDuration": "00:00:00",
"maxDuration": "00:00:00",
"seasonality": "mediu",
"equipmentLevel": null,
"trailMarking": null,
"hasTrailType": false
},
I was thinking maybe it's EF Core, and have made this 2nd try (i.e. added Include() to dbContext query):
[HttpGet("[action]")]
public IEnumerable<HikingTrail> HikingTrails()
{
var dbOptions = new DbContextOptionsBuilder<HikingTrailContext>();
dbOptions.UseSqlServer("Server = (localdb)\\mssqllocaldb; Database = HikingApp");
var dbContext = new DAO.HikingTrailContext(dbOptions.Options);
return dbContext.HikingTrails.Include( x => x.MountainRange).ToList();
}
Could not get any response in Postman.
EDIT:
public class HikingTrailContext : DbContext
{
public HikingTrailContext(DbContextOptions<HikingTrailContext> options) : base(options)
{
}
public HikingTrailContext():base(){
}
public DbSet<HikingTrail> HikingTrails { get; set; }
public DbSet<MountainRange> MountainRanges { get; set; }
public DbSet<TrailScrapingSessionInfo> TrailScrapingHistory { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
}
public class HikingTrail
{
[Key]
public int HikingTrailId { get; set; }
public HikingTrail() { }
public MountainRange MountainRange { get; set; }
public String Name { get; set; }
public Location StartPoint { get; set; }
public Location EndPoint { get; set; }
public List<Location> TrailCheckpoints { get; }
public TrailType Type => TrailType.Undetermined;
public String Dificulty { get; set; }
public String Duration { get; set; }
public TimeSpan MinDuration { get; set; }
public TimeSpan MaxDuration { get; set; }
public String Seasonality { get; set; }
public String EquipmentLevel { get; set; }
public String TrailMarking { get; set; }
public String URL;
public bool HasTrailType
{
get
{
return this.Type != TrailType.Undetermined;
}
}
public override bool Equals(object obj)
{
return (((HikingTrail)obj).Name == this.Name);
}
public override int GetHashCode()
{
int hash = 17;
// Suitable nullity checks etc, of course :)
hash = hash * 23 + Name.GetHashCode();
hash = hash * 23 + Type.GetHashCode();
hash = hash * 23 + StartPoint.GetHashCode();
return hash;
}
public override string ToString()
{
return Name.ToString();
}
}
EDIT :
I profiled the db on dbContext.HikingTrails.Include(x => x.MountainRange).Where(x => x.MountainRange != null).ToList(); and the generated query is OK, meaning it has a Name column for MountainRange as well.
P.S.: several fields are null, but those ones don't have data yet.
found one solution, Projection to an anonymous type. Also had to be careful not to have two fields with the same name of "Name"
[HttpGet("[action]")]
public dynamic HikingTrails3()
{
var dbOptions = new DbContextOptionsBuilder<HikingTrailContext>();
dbOptions.UseSqlServer("Server = (localdb)\\mssqllocaldb; Database = HikingApp");
var dbContext = new DAO.HikingTrailContext(dbOptions.Options);
var trails = dbContext.HikingTrails.Include(x => x.MountainRange).
Select( i =>new { Name= i.Name, MountainRangeName = i.MountainRange.Name, i.Duration,
i.Dificulty,i.EquipmentLevel, i.Seasonality, i.Type }).ToList();
return trails;
}
I'm trying to figure out how to pull values from a SQL database and display this in a razor view.
I have the following class using Entity Framework (I believe)
public class EventLog
{
[Key]
public int Id { get; set; }
public int EventId { get; set; }
public int MaxDelegates { get; set; }
public string Code { get; set; }
public DateTime End { get; set; }
public string Title { get; set; }
}
And I want to map title to DBTitle in the following model:
public class CourseDetailVM : CourseDetailSummaryVM
{
public EventLog DBTitle { get; set; }
}
I then want to see this in the following view:
#using TSW.Web.Helpers
#model TSW.Web.ViewModels.CourseDetailVM
#{
Layout = "~/Views/_Master.cshtml";
}
#Model.DBTitle.Title;
I have the following controller already in place (sorry for the length I plan to reduce this down):
public class CourseDetailController : BaseRenderController<CourseDetailPageDT>
{
private readonly ISitePageFactory _pageFactory = null;
private readonly IEventService _eventService = null;
public CourseDetailController(IEventService eventService, ISitePageFactory pageFactory)
{
_pageFactory = pageFactory;
_eventService = eventService;
}
public async Task<ActionResult> CourseDetail()
{
var homepage = _pageFactory.GetCurrentHomepage();
var model = Mapper.Map<CourseDetailVM>(CurrentContent);
model.Email = homepage.ContactEmail;
model.PhoneNumber = homepage.HeaderPhoneNumber;
model.InnerPageHeader.ShowHeading = true;
model.InnerPageHeader.Title = model.PageTitle;
if (model.Categories.Count == 1)
{
var categoryTagId = model.Categories.First().Id;
var contentTypeAlias = DocumentTypeHelper.GetDocumentTypeAlias<CourseListingPageDT>();
var courseCategoryPage = Umbraco.TypedContentAtXPath($"//{contentTypeAlias}")
.FirstOrDefault(x => x.GetPropertyValue<int>(Constants.DocumentTypes.CourseListingPage.Category) == categoryTagId);
if (courseCategoryPage != null)
{
model.InnerPageHeader.BackLink = Mapper.Map<LinkItem>(courseCategoryPage.Id);
}
}
try
{
model.Events = await _eventService.GetEventsForCourse(CurrentContent.AdministrateId);
}
catch (Exception ex)
{
model.Events = new StaticPagedList<Event>(Enumerable.Empty<Event>(), 1, 1, 0);
Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
}
if (CurrentContent.Graphic != 0)
{
model.InnerPageHeader.Graphic = Mapper.Map<CtaItem>(CurrentContent.Graphic);
}
return View(model);
}
}
I've tried every suggestion I can google to add the mapping in the controlling but can't get my head around this simple function of pulling the value from a SQL database into the razor view.
Could anyone help me out?
I'm trying to define an index in RavenDb that uses the output of another index as it's input but I can't get it to work.
I have the following entities & indexes defined.
SquadIndex produces the result I expect it to do but SquadSizeIndex doesn't even seem to execute.
Have I done something wrong or is this not supported?
class Country
{
public string Id { get; private set; }
public string Name { get; set; }
}
class Player
{
public string Id { get; private set; }
public string Name { get; set; }
public string CountryId { get; set; }
}
class Reference
{
public string Id { get; set; }
public string Name { get; set; }
}
class SquadIndex : AbstractIndexCreationTask<Player, SquadIndex.Result>
{
public SquadIndex()
{
Map = players => from player in players
let country = LoadDocument<Country>(player.CountryId)
select new Result
{
Country = new Reference
{
Id = country.Id,
Name = country.Name
},
Players = new[]
{
new Reference
{
Id = player.Id,
Name = player.Name
}
}
};
Reduce = results => from result in results
group result by result.Country
into g
select new Result
{
Country = g.Key,
Players = g.SelectMany(x => x.Players)
};
}
internal class Result
{
public Reference Country { get; set; }
public IEnumerable<Reference> Players { get; set; }
}
}
class SquadSizeIndex : AbstractIndexCreationTask<SquadIndex.Result, SquadSizeIndex.Result>
{
public SquadSizeIndex()
{
Map = squads => from squad in squads
select new Result
{
Country = squad.Country,
PlayerCount = squad.Players.Count()
};
Reduce = results => from result in results
group result by result.Country
into g
select new Result
{
Country = g.Key,
PlayerCount = g.Sum(x => x.PlayerCount)
};
}
internal class Result
{
public Reference Country { get; set; }
public int PlayerCount { get; set; }
}
}
No, you can't. The output of indexes are not documents to be indexed.
You can use the scripted index results to chain indexes, but that isn't trivial.
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